| /cvi/instr/drsctrl/DRS.cpp |
|---|
| 0,0 → 1,7733 |
| /******************************************************************** |
| Name: DRS.cpp |
| Created by: Stefan Ritt, Matthias Schneebeli |
| Contents: Library functions for DRS mezzanine and USB boards |
| $Id: DRS.cpp 22289 2016-04-27 09:40:58Z ritt $ |
| \********************************************************************/ |
| #define NEW_TIMING_CALIBRATION |
| #ifdef USE_DRS_MUTEX |
| #include "wx/wx.h" // must be before <windows.h> |
| #endif |
| #include <stdio.h> |
| #include <math.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <time.h> |
| #include <assert.h> |
| #include <algorithm> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include "strlcpy.h" |
| #include "DRS.h" |
| #ifdef _MSC_VER |
| #pragma warning(disable:4996) |
| # include <windows.h> |
| # include <direct.h> |
| #else |
| # include <unistd.h> |
| # include <sys/time.h> |
| inline void Sleep(useconds_t x) |
| { |
| usleep(x * 1000); |
| } |
| #endif |
| #ifdef _MSC_VER |
| #include <conio.h> |
| #define drs_kbhit() kbhit() |
| #else |
| #include <sys/ioctl.h> |
| int drs_kbhit() |
| { |
| int n; |
| ioctl(0, FIONREAD, &n); |
| return (n > 0); |
| } |
| static inline int getch() |
| { |
| return getchar(); |
| } |
| #endif |
| #include "DRS.h" |
| #ifdef _MSC_VER |
| extern "C" { |
| #endif |
| #include "mxml.h" |
| #ifdef _MSC_VER |
| } |
| #endif |
| /*---- minimal FPGA firmvare version required for this library -----*/ |
| const int REQUIRED_FIRMWARE_VERSION_DRS2 = 5268; |
| const int REQUIRED_FIRMWARE_VERSION_DRS3 = 6981; |
| const int REQUIRED_FIRMWARE_VERSION_DRS4 = 15147; |
| /*---- calibration methods to be stored in EEPROMs -----------------*/ |
| #define VCALIB_METHOD_V4 1 |
| #define TCALIB_METHOD_V4 1 |
| #define VCALIB_METHOD 2 |
| #define TCALIB_METHOD 2 // correct for sampling frequency, calibrate every channel |
| /*---- VME addresses -----------------------------------------------*/ |
| #ifdef HAVE_VME |
| /* assuming following DIP Switch settings: |
| SW1-1: 1 (off) use geographical addressing (1=left, 21=right) |
| SW1-2: 1 (off) \ |
| SW1-3: 1 (off) > VME_WINSIZE = 8MB, subwindow = 1MB |
| SW1-4: 0 (on) / |
| SW1-5: 0 (on) reserverd |
| SW1-6: 0 (on) reserverd |
| SW1-7: 0 (on) reserverd |
| SW1-8: 0 (on) \ |
| | |
| SW2-1: 0 (on) | |
| SW2-2: 0 (on) | |
| SW2-3: 0 (on) | |
| SW2-4: 0 (on) > VME_ADDR_OFFSET = 0 |
| SW2-5: 0 (on) | |
| SW2-6: 0 (on) | |
| SW2-7: 0 (on) | |
| SW2-8: 0 (on) / |
| which gives |
| VME base address = SlotNo * VME_WINSIZE + VME_ADDR_OFFSET |
| = SlotNo * 0x80'0000 |
| */ |
| #define GEVPC_BASE_ADDR 0x00000000 |
| #define GEVPC_WINSIZE 0x800000 |
| #define GEVPC_USER_FPGA (GEVPC_WINSIZE*2/8) |
| #define PMC1_OFFSET 0x00000 |
| #define PMC2_OFFSET 0x80000 |
| #define PMC_CTRL_OFFSET 0x00000 /* all registers 32 bit */ |
| #define PMC_STATUS_OFFSET 0x10000 |
| #define PMC_FIFO_OFFSET 0x20000 |
| #define PMC_RAM_OFFSET 0x40000 |
| #endif // HAVE_VME |
| /*---- USB addresses -----------------------------------------------*/ |
| #define USB_TIMEOUT 1000 // one second |
| #ifdef HAVE_USB |
| #define USB_CTRL_OFFSET 0x00 /* all registers 32 bit */ |
| #define USB_STATUS_OFFSET 0x40 |
| #define USB_RAM_OFFSET 0x80 |
| #define USB_CMD_IDENT 0 // Query identification |
| #define USB_CMD_ADDR 1 // Address cycle |
| #define USB_CMD_READ 2 // "VME" read <addr><size> |
| #define USB_CMD_WRITE 3 // "VME" write <addr><size> |
| #define USB_CMD_READ12 4 // 12-bit read <LSB><MSB> |
| #define USB_CMD_WRITE12 5 // 12-bit write <LSB><MSB> |
| #define USB2_CMD_READ 1 |
| #define USB2_CMD_WRITE 2 |
| #define USB2_CTRL_OFFSET 0x00000 /* all registers 32 bit */ |
| #define USB2_STATUS_OFFSET 0x10000 |
| #define USB2_FIFO_OFFSET 0x20000 |
| #define USB2_RAM_OFFSET 0x40000 |
| #endif // HAVE_USB |
| /*------------------------------------------------------------------*/ |
| using namespace std; |
| #ifdef HAVE_USB |
| #define USB2_BUFFER_SIZE (1024*1024+10) |
| unsigned char static *usb2_buffer = NULL; |
| #endif |
| /*------------------------------------------------------------------*/ |
| #ifdef USE_DRS_MUTEX |
| static wxMutex *s_drsMutex = NULL; // used for wxWidgets multi-threaded programs |
| #endif |
| /*------------------------------------------------------------------*/ |
| DRS::DRS() |
| : fNumberOfBoards(0) |
| #ifdef HAVE_VME |
| , fVmeInterface(0) |
| #endif |
| { |
| #ifdef HAVE_USB |
| MUSB_INTERFACE *usb_interface; |
| #endif |
| #if defined(HAVE_VME) || defined(HAVE_USB) |
| int index = 0, i=0; |
| #endif |
| memset(fError, 0, sizeof(fError)); |
| #ifdef HAVE_VME |
| unsigned short type, fw, magic, serial, temperature; |
| mvme_addr_t addr; |
| if (mvme_open(&fVmeInterface, 0) == MVME_SUCCESS) { |
| mvme_set_am(fVmeInterface, MVME_AM_A32); |
| mvme_set_dmode(fVmeInterface, MVME_DMODE_D16); |
| /* check all VME slave slots */ |
| for (index = 2; index <= 21; index++) { |
| /* check PMC1 */ |
| addr = GEVPC_BASE_ADDR + index * GEVPC_WINSIZE; // VME board base address |
| addr += GEVPC_USER_FPGA; // UsrFPGA base address |
| addr += PMC1_OFFSET; // PMC1 offset |
| mvme_set_dmode(fVmeInterface, MVME_DMODE_D16); |
| i = mvme_read(fVmeInterface, &magic, addr + PMC_STATUS_OFFSET + REG_MAGIC, 2); |
| if (i == 2) { |
| if (magic != 0xC0DE) { |
| printf("Found old firmware, please upgrade immediately!\n"); |
| fBoard[fNumberOfBoards] = new DRSBoard(fVmeInterface, addr, (index - 2) << 1); |
| fNumberOfBoards++; |
| } else { |
| /* read board type */ |
| mvme_read(fVmeInterface, &type, addr + PMC_STATUS_OFFSET + REG_BOARD_TYPE, 2); |
| type &= 0xFF; |
| if (type == 2 || type == 3 || type == 4) { // DRS2 or DRS3 or DRS4 |
| /* read firmware number */ |
| mvme_read(fVmeInterface, &fw, addr + PMC_STATUS_OFFSET + REG_VERSION_FW, 2); |
| /* read serial number */ |
| mvme_read(fVmeInterface, &serial, addr + PMC_STATUS_OFFSET + REG_SERIAL_BOARD, 2); |
| /* read temperature register to see if CMC card is present */ |
| mvme_read(fVmeInterface, &temperature, addr + PMC_STATUS_OFFSET + REG_TEMPERATURE, 2); |
| /* LED blinking */ |
| #if 0 |
| do { |
| data = 0x00040000; |
| mvme_write(fVmeInterface, addr + PMC_CTRL_OFFSET + REG_CTRL, &data, sizeof(data)); |
| mvme_write(fVmeInterface, addr + PMC2_OFFSET + PMC_CTRL_OFFSET + REG_CTRL, &data, |
| sizeof(data)); |
| Sleep(500); |
| data = 0x00000000; |
| mvme_write(fVmeInterface, addr + PMC_CTRL_OFFSET + REG_CTRL, &data, sizeof(data)); |
| mvme_write(fVmeInterface, addr + PMC2_OFFSET + PMC_CTRL_OFFSET + REG_CTRL, data, |
| sizeof(data)); |
| Sleep(500); |
| } while (1); |
| #endif |
| if (temperature == 0xFFFF) { |
| printf("Found VME board in slot %d, fw %d, but no CMC board in upper slot\n", index, fw); |
| } else { |
| printf("Found DRS%d board %2d in upper VME slot %2d, serial #%d, firmware revision %d\n", type, fNumberOfBoards, index, serial, fw); |
| fBoard[fNumberOfBoards] = new DRSBoard(fVmeInterface, addr, (index - 2) << 1); |
| if (!fBoard[fNumberOfBoards]->HasCorrectFirmware()) |
| sprintf(fError, "Wrong firmware version: board has %d, required is %d. Board may not work correctly.\n", |
| fBoard[fNumberOfBoards]->GetFirmwareVersion(), |
| fBoard[fNumberOfBoards]->GetRequiredFirmwareVersion()); |
| fNumberOfBoards++; |
| } |
| } |
| } |
| } |
| /* check PMC2 */ |
| addr = GEVPC_BASE_ADDR + index * GEVPC_WINSIZE; // VME board base address |
| addr += GEVPC_USER_FPGA; // UsrFPGA base address |
| addr += PMC2_OFFSET; // PMC2 offset |
| mvme_set_dmode(fVmeInterface, MVME_DMODE_D16); |
| i = mvme_read(fVmeInterface, &fw, addr + PMC_STATUS_OFFSET + REG_MAGIC, 2); |
| if (i == 2) { |
| if (magic != 0xC0DE) { |
| printf("Found old firmware, please upgrade immediately!\n"); |
| fBoard[fNumberOfBoards] = new DRSBoard(fVmeInterface, addr, (index - 2) << 1 | 1); |
| fNumberOfBoards++; |
| } else { |
| /* read board type */ |
| mvme_read(fVmeInterface, &type, addr + PMC_STATUS_OFFSET + REG_BOARD_TYPE, 2); |
| type &= 0xFF; |
| if (type == 2 || type == 3 || type == 4) { // DRS2 or DRS3 or DRS4 |
| /* read firmware number */ |
| mvme_read(fVmeInterface, &fw, addr + PMC_STATUS_OFFSET + REG_VERSION_FW, 2); |
| /* read serial number */ |
| mvme_read(fVmeInterface, &serial, addr + PMC_STATUS_OFFSET + REG_SERIAL_BOARD, 2); |
| /* read temperature register to see if CMC card is present */ |
| mvme_read(fVmeInterface, &temperature, addr + PMC_STATUS_OFFSET + REG_TEMPERATURE, 2); |
| if (temperature == 0xFFFF) { |
| printf("Found VME board in slot %d, fw %d, but no CMC board in lower slot\n", index, fw); |
| } else { |
| printf("Found DRS%d board %2d in lower VME slot %2d, serial #%d, firmware revision %d\n", type, fNumberOfBoards, index, serial, fw); |
| fBoard[fNumberOfBoards] = new DRSBoard(fVmeInterface, addr, ((index - 2) << 1) | 1); |
| if (!fBoard[fNumberOfBoards]->HasCorrectFirmware()) |
| sprintf(fError, "Wrong firmware version: board has %d, required is %d. Board may not work correctly.\n", |
| fBoard[fNumberOfBoards]->GetFirmwareVersion(), |
| fBoard[fNumberOfBoards]->GetRequiredFirmwareVersion()); |
| fNumberOfBoards++; |
| } |
| } |
| } |
| } |
| } |
| } else |
| printf("Cannot access VME crate, check driver, power and connection\n"); |
| #endif // HAVE_VME |
| #ifdef HAVE_USB |
| unsigned char buffer[512]; |
| int found, one_found, usb_slot; |
| one_found = 0; |
| usb_slot = 0; |
| for (index = 0; index < 127; index++) { |
| found = 0; |
| /* check for USB-Mezzanine test board */ |
| if (musb_open(&usb_interface, 0x10C4, 0x1175, index, 1, 0) == MUSB_SUCCESS) { |
| /* check ID */ |
| buffer[0] = USB_CMD_IDENT; |
| musb_write(usb_interface, 2, buffer, 1, USB_TIMEOUT); |
| i = musb_read(usb_interface, 1, (char *) buffer, sizeof(buffer), USB_TIMEOUT); |
| if (strcmp((char *) buffer, "USB_MEZZ2 V1.0") != 0) { |
| /* no USB-Mezzanine board found */ |
| musb_close(usb_interface); |
| } else { |
| usb_interface->usb_type = 1; // USB 1.1 |
| fBoard[fNumberOfBoards] = new DRSBoard(usb_interface, usb_slot++); |
| if (!fBoard[fNumberOfBoards]->HasCorrectFirmware()) |
| sprintf(fError, "Wrong firmware version: board has %d, required is %d. Board may not work correctly.\n", |
| fBoard[fNumberOfBoards]->GetFirmwareVersion(), |
| fBoard[fNumberOfBoards]->GetRequiredFirmwareVersion()); |
| fNumberOfBoards++; |
| found = 1; |
| one_found = 1; |
| } |
| } |
| /* check for DRS4 evaluation board */ |
| if (musb_open(&usb_interface, 0x04B4, 0x1175, index, 1, 0) == MUSB_SUCCESS) { |
| /* check ID */ |
| if (musb_get_device(usb_interface) != 1) { |
| /* no DRS evaluation board found */ |
| musb_close(usb_interface); |
| } else { |
| /* drain any data from Cy7C68013 FIFO if FPGA startup caused erratic write */ |
| do { |
| i = musb_read(usb_interface, 8, buffer, sizeof(buffer), 100); |
| if (i > 0) |
| printf("%d bytes stuck in buffer\n", i); |
| } while (i > 0); |
| usb_interface->usb_type = 2; // USB 2.0 |
| fBoard[fNumberOfBoards] = new DRSBoard(usb_interface, usb_slot++); |
| if (!fBoard[fNumberOfBoards]->HasCorrectFirmware()) |
| sprintf(fError, "Wrong firmware version: board has %d, required is %d. Board may not work correctly.\n", |
| fBoard[fNumberOfBoards]->GetFirmwareVersion(), |
| fBoard[fNumberOfBoards]->GetRequiredFirmwareVersion()); |
| fNumberOfBoards++; |
| found = 1; |
| one_found = 1; |
| } |
| } |
| if (!found) { |
| if (!one_found) |
| printf("USB successfully scanned, but no boards found\n"); |
| break; |
| } |
| } |
| #endif // HAVE_USB |
| return; |
| } |
| /*------------------------------------------------------------------*/ |
| DRS::~DRS() |
| { |
| int i; |
| for (i = 0; i < fNumberOfBoards; i++) { |
| delete fBoard[i]; |
| } |
| #ifdef HAVE_USB |
| if (usb2_buffer) { |
| free(usb2_buffer); |
| usb2_buffer = NULL; |
| } |
| #endif |
| #ifdef HAVE_VME |
| mvme_close(fVmeInterface); |
| #endif |
| } |
| /*------------------------------------------------------------------*/ |
| void DRS::SortBoards() |
| { |
| /* sort boards according to serial number (simple bubble sort) */ |
| for (int i=0 ; i<fNumberOfBoards-1 ; i++) { |
| for (int j=i+1 ; j<fNumberOfBoards ; j++) { |
| if (fBoard[i]->GetBoardSerialNumber() < fBoard[j]->GetBoardSerialNumber()) { |
| DRSBoard* b = fBoard[i]; |
| fBoard[i] = fBoard[j]; |
| fBoard[j] = b; |
| } |
| } |
| } |
| } |
| /*------------------------------------------------------------------*/ |
| void DRS::SetBoard(int i, DRSBoard *b) |
| { |
| fBoard[i] = b; |
| } |
| /*------------------------------------------------------------------*/ |
| bool DRS::GetError(char *str, int size) |
| { |
| if (fError[0]) |
| strlcpy(str, fError, size); |
| return fError[0] > 0; |
| } |
| /*------------------------------------------------------------------*/ |
| #ifdef HAVE_USB |
| DRSBoard::DRSBoard(MUSB_INTERFACE * musb_interface, int usb_slot) |
| : fDAC_COFSA(0) |
| , fDAC_COFSB(0) |
| , fDAC_DRA(0) |
| , fDAC_DSA(0) |
| , fDAC_TLEVEL(0) |
| , fDAC_ACALIB(0) |
| , fDAC_DSB(0) |
| , fDAC_DRB(0) |
| , fDAC_COFS(0) |
| , fDAC_ADCOFS(0) |
| , fDAC_CLKOFS(0) |
| , fDAC_ROFS_1(0) |
| , fDAC_ROFS_2(0) |
| , fDAC_INOFS(0) |
| , fDAC_BIAS(0) |
| , fDRSType(0) |
| , fBoardType(0) |
| , fRequiredFirmwareVersion(0) |
| , fFirmwareVersion(0) |
| , fBoardSerialNumber(0) |
| , fHasMultiBuffer(0) |
| , fCtrlBits(0) |
| , fNumberOfReadoutChannels(0) |
| , fReadoutChannelConfig(0) |
| , fADCClkPhase(0) |
| , fADCClkInvert(0) |
| , fExternalClockFrequency(0) |
| , fUsbInterface(musb_interface) |
| #ifdef HAVE_VME |
| , fVmeInterface(0) |
| , fBaseAddress(0) |
| #endif |
| , fSlotNumber(usb_slot) |
| , fNominalFrequency(0) |
| , fMultiBuffer(0) |
| , fDominoMode(0) |
| , fDominoActive(0) |
| , fChannelConfig(0) |
| , fChannelCascading(1) |
| , fChannelDepth(1024) |
| , fWSRLoop(0) |
| , fReadoutMode(0) |
| , fReadPointer(0) |
| , fNMultiBuffer(0) |
| , fTriggerEnable1(0) |
| , fTriggerEnable2(0) |
| , fTriggerSource(0) |
| , fTriggerDelay(0) |
| , fTriggerDelayNs(0) |
| , fSyncDelay(0) |
| , fDelayedStart(0) |
| , fTranspMode(0) |
| , fDecimation(0) |
| , fRange(0) |
| , fCommonMode(0.8) |
| , fAcalMode(0) |
| , fAcalVolt(0) |
| , fTcalFreq(0) |
| , fTcalLevel(0) |
| , fTcalPhase(0) |
| , fTcalSource(0) |
| , fRefclk(0) |
| , fMaxChips(0) |
| , fResponseCalibration(0) |
| , fVoltageCalibrationValid(false) |
| , fCellCalibratedRange(0) |
| , fCellCalibratedTemperature(0) |
| , fTimeData(0) |
| , fNumberOfTimeData(0) |
| , fDebug(0) |
| , fTriggerStartBin(0) |
| { |
| if (musb_interface->usb_type == 1) |
| fTransport = TR_USB; |
| else |
| fTransport = TR_USB2; |
| memset(fStopCell, 0, sizeof(fStopCell)); |
| memset(fStopWSR, 0, sizeof(fStopWSR)); |
| fTriggerBus = 0; |
| ConstructBoard(); |
| } |
| #endif |
| #ifdef HAVE_VME |
| /*------------------------------------------------------------------*/ |
| DRSBoard::DRSBoard(MVME_INTERFACE * mvme_interface, mvme_addr_t base_address, int slot_number) |
| :fDAC_COFSA(0) |
| , fDAC_COFSB(0) |
| , fDAC_DRA(0) |
| , fDAC_DSA(0) |
| , fDAC_TLEVEL(0) |
| , fDAC_ACALIB(0) |
| , fDAC_DSB(0) |
| , fDAC_DRB(0) |
| , fDAC_COFS(0) |
| , fDAC_ADCOFS(0) |
| , fDAC_CLKOFS(0) |
| , fDAC_ROFS_1(0) |
| , fDAC_ROFS_2(0) |
| , fDAC_INOFS(0) |
| , fDAC_BIAS(0) |
| , fDRSType(0) |
| , fBoardType(0) |
| , fRequiredFirmwareVersion(0) |
| , fFirmwareVersion(0) |
| , fBoardSerialNumber(0) |
| , fHasMultiBuffer(0) |
| , fTransport(TR_VME) |
| , fCtrlBits(0) |
| , fNumberOfReadoutChannels(0) |
| , fReadoutChannelConfig(0) |
| , fADCClkPhase(0) |
| , fADCClkInvert(0) |
| , fExternalClockFrequency(0) |
| #ifdef HAVE_USB |
| , fUsbInterface(0) |
| #endif |
| #ifdef HAVE_VME |
| , fVmeInterface(mvme_interface) |
| , fBaseAddress(base_address) |
| , fSlotNumber(slot_number) |
| #endif |
| , fNominalFrequency(0) |
| , fRefClock(0) |
| , fMultiBuffer(0) |
| , fDominoMode(1) |
| , fDominoActive(1) |
| , fChannelConfig(0) |
| , fChannelCascading(1) |
| , fChannelDepth(1024) |
| , fWSRLoop(1) |
| , fReadoutMode(0) |
| , fReadPointer(0) |
| , fNMultiBuffer(0) |
| , fTriggerEnable1(0) |
| , fTriggerEnable2(0) |
| , fTriggerSource(0) |
| , fTriggerDelay(0) |
| , fTriggerDelayNs(0) |
| , fSyncDelay(0) |
| , fDelayedStart(0) |
| , fTranspMode(0) |
| , fDecimation(0) |
| , fRange(0) |
| , fCommonMode(0.8) |
| , fAcalMode(0) |
| , fAcalVolt(0) |
| , fTcalFreq(0) |
| , fTcalLevel(0) |
| , fTcalPhase(0) |
| , fTcalSource(0) |
| , fRefclk(0) |
| , fMaxChips(0) |
| , fResponseCalibration(0) |
| , fTimeData(0) |
| , fNumberOfTimeData(0) |
| , fDebug(0) |
| , fTriggerStartBin(0) |
| { |
| ConstructBoard(); |
| } |
| #endif |
| /*------------------------------------------------------------------*/ |
| DRSBoard::~DRSBoard() |
| { |
| int i; |
| #ifdef HAVE_USB |
| if (fTransport == TR_USB || fTransport == TR_USB2) |
| musb_close(fUsbInterface); |
| #endif |
| #ifdef USE_DRS_MUTEX |
| if (s_drsMutex) |
| delete s_drsMutex; |
| s_drsMutex = NULL; |
| #endif |
| // Response Calibration |
| delete fResponseCalibration; |
| // Time Calibration |
| for (i = 0; i < fNumberOfTimeData; i++) { |
| delete fTimeData[i]; |
| } |
| delete[]fTimeData; |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::ConstructBoard() |
| { |
| unsigned char buffer[2]; |
| unsigned int bits; |
| fDebug = 0; |
| fWSRLoop = 1; |
| fCtrlBits = 0; |
| fExternalClockFrequency = 1000. / 30.; |
| strcpy(fCalibDirectory, "."); |
| /* check board communication */ |
| if (Read(T_STATUS, buffer, REG_MAGIC, 2) < 0) { |
| InitFPGA(); |
| if (Read(T_STATUS, buffer, REG_MAGIC, 2) < 0) |
| return; |
| } |
| ReadSerialNumber(); |
| /* set correct reference clock */ |
| if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) |
| fRefClock = 60; |
| else |
| fRefClock = 33; |
| /* get mode from hardware */ |
| bits = GetCtrlReg(); |
| fMultiBuffer = (bits & BIT_MULTI_BUFFER) > 0; |
| fNMultiBuffer = 0; |
| if (fHasMultiBuffer && fMultiBuffer) |
| fNMultiBuffer = 3; |
| if (fDRSType == 4) { |
| fDominoMode = (bits & BIT_CONFIG_DMODE) > 0; |
| } else { |
| fDominoMode = (bits & BIT_DMODE) > 0; |
| } |
| fTriggerEnable1 = (bits & BIT_ENABLE_TRIGGER1) > 0; |
| fTriggerEnable2 = (bits & BIT_ENABLE_TRIGGER2) > 0; |
| fTriggerSource = ((bits & BIT_TR_SOURCE1) > 0) | (((bits & BIT_TR_SOURCE2) > 0) << 1); |
| fReadoutMode = (bits & BIT_READOUT_MODE) > 0; |
| Read(T_CTRL, &fReadPointer, REG_READ_POINTER, 2); |
| fADCClkInvert = (bits & BIT_ADCCLK_INVERT) > 0; |
| fDominoActive = (bits & BIT_DACTIVE) > 0; |
| ReadFrequency(0, &fNominalFrequency); |
| if (fNominalFrequency < 0.1 || fNominalFrequency > 6) |
| fNominalFrequency = 1; |
| /* initialize number of channels */ |
| if (fDRSType == 4) { |
| if (fBoardType == 6) { |
| unsigned short d; |
| Read(T_CTRL, &d, REG_CHANNEL_MODE, 2); |
| fReadoutChannelConfig = d & 0xFF; |
| if (d == 7) |
| fNumberOfReadoutChannels = 9; |
| else |
| fNumberOfReadoutChannels = 5; |
| } else |
| fNumberOfReadoutChannels = 9; |
| } else |
| fNumberOfReadoutChannels = 10; |
| if (fBoardType == 1) { |
| fDAC_COFSA = 0; |
| fDAC_COFSB = 1; |
| fDAC_DRA = 2; |
| fDAC_DSA = 3; |
| fDAC_TLEVEL = 4; |
| fDAC_ACALIB = 5; |
| fDAC_DSB = 6; |
| fDAC_DRB = 7; |
| } else if (fBoardType == 2 || fBoardType == 3) { |
| fDAC_COFS = 0; |
| fDAC_DSA = 1; |
| fDAC_DSB = 2; |
| fDAC_TLEVEL = 3; |
| fDAC_CLKOFS = 5; |
| fDAC_ACALIB = 6; |
| fDAC_ADCOFS = 7; |
| } else if (fBoardType == 4) { |
| fDAC_ROFS_1 = 0; |
| fDAC_DSA = 1; |
| fDAC_DSB = 2; |
| fDAC_ROFS_2 = 3; |
| fDAC_BIAS = 4; |
| fDAC_INOFS = 5; |
| fDAC_ACALIB = 6; |
| fDAC_ADCOFS = 7; |
| } else if (fBoardType == 5) { |
| fDAC_ROFS_1 = 0; |
| fDAC_CMOFS = 1; |
| fDAC_CALN = 2; |
| fDAC_CALP = 3; |
| fDAC_BIAS = 4; |
| fDAC_TLEVEL = 5; |
| fDAC_ONOFS = 6; |
| } else if (fBoardType == 6) { |
| fDAC_ONOFS = 0; |
| fDAC_CMOFSP = 1; |
| fDAC_CALN = 2; |
| fDAC_CALP = 3; |
| fDAC_CMOFSN = 5; |
| fDAC_ROFS_1 = 6; |
| fDAC_BIAS = 7; |
| } else if (fBoardType == 7) { |
| fDAC_ROFS_1 = 0; |
| fDAC_CMOFS = 1; |
| fDAC_CALN = 2; |
| fDAC_CALP = 3; |
| fDAC_BIAS = 4; |
| fDAC_TLEVEL = 5; |
| fDAC_ONOFS = 6; |
| } else if (fBoardType == 8 || fBoardType == 9) { |
| fDAC_ROFS_1 = 0; |
| fDAC_TLEVEL4 = 1; |
| fDAC_CALN = 2; |
| fDAC_CALP = 3; |
| fDAC_BIAS = 4; |
| fDAC_TLEVEL1 = 5; |
| fDAC_TLEVEL2 = 6; |
| fDAC_TLEVEL3 = 7; |
| } |
| if (fDRSType < 4) { |
| // Response Calibration |
| fResponseCalibration = new ResponseCalibration(this); |
| // Time Calibration |
| fTimeData = new DRSBoard::TimeData *[kNumberOfChipsMax]; |
| fNumberOfTimeData = 0; |
| } |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::ReadSerialNumber() |
| { |
| unsigned char buffer[2]; |
| int number; |
| // check magic number |
| if (Read(T_STATUS, buffer, REG_MAGIC, 2) < 0) { |
| printf("Cannot read from board\n"); |
| return; |
| } |
| number = (static_cast < int >(buffer[1]) << 8) +buffer[0]; |
| if (number != 0xC0DE) { |
| printf("Invalid magic number: %04X\n", number); |
| return; |
| } |
| // read board type |
| Read(T_STATUS, buffer, REG_BOARD_TYPE, 2); |
| fDRSType = buffer[0]; |
| fBoardType = buffer[1]; |
| // read firmware version |
| Read(T_STATUS, buffer, REG_VERSION_FW, 2); |
| fFirmwareVersion = (static_cast < int >(buffer[1]) << 8) +buffer[0]; |
| // retrieve board serial number |
| Read(T_STATUS, buffer, REG_SERIAL_BOARD, 2); |
| number = (static_cast < int >(buffer[1]) << 8) +buffer[0]; |
| fBoardSerialNumber = number; |
| // determine DRS type and board type for old boards from setial number |
| if (fBoardType == 0) { |
| // determine board version from serial number |
| if (number >= 2000 && number < 5000) { |
| fBoardType = 6; |
| fDRSType = 4; |
| } else if (number >= 1000) { |
| fBoardType = 4; |
| fDRSType = 3; |
| } else if (number >= 100) |
| fBoardType = 3; |
| else if (number > 0) |
| fBoardType = 2; |
| else { |
| fBoardType = 3; |
| fDRSType = 2; |
| fRequiredFirmwareVersion = REQUIRED_FIRMWARE_VERSION_DRS2; |
| } |
| } |
| // set constants according to board type |
| if (fBoardType == 6) |
| fNumberOfChips = 4; |
| else |
| fNumberOfChips = 1; |
| if (fDRSType == 4) |
| fNumberOfChannels = 9; |
| else |
| fNumberOfChannels = 10; |
| // retrieve firmware version |
| if (fDRSType == 2) |
| fRequiredFirmwareVersion = REQUIRED_FIRMWARE_VERSION_DRS2; |
| if (fDRSType == 3) |
| fRequiredFirmwareVersion = REQUIRED_FIRMWARE_VERSION_DRS3; |
| if (fDRSType == 4) |
| fRequiredFirmwareVersion = REQUIRED_FIRMWARE_VERSION_DRS4; |
| fHasMultiBuffer = ((fBoardType == 6) && fTransport == TR_VME); |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::ReadCalibration(void) |
| { |
| unsigned short buf[1024*16]; // 32 kB |
| int i, j, chip; |
| fVoltageCalibrationValid = false; |
| fTimingCalibratedFrequency = 0; |
| memset(fCellOffset, 0, sizeof(fCellOffset)); |
| memset(fCellGain, 0, sizeof(fCellGain)); |
| memset(fCellOffset2, 0, sizeof(fCellOffset2)); |
| memset(fCellDT, 0, sizeof(fCellDT)); |
| /* read offsets and gain from eeprom */ |
| if (fBoardType == 9) { |
| memset(buf, 0, sizeof(buf)); |
| ReadEEPROM(0, buf, 4096); |
| /* check voltage calibration method */ |
| if ((buf[2] & 0xFF) == VCALIB_METHOD) |
| fVoltageCalibrationValid = true; |
| else { |
| fCellCalibratedRange = 0; |
| fCellCalibratedTemperature = -100; |
| return; |
| } |
| /* check timing calibration method */ |
| if ((buf[2] >> 8) == TCALIB_METHOD) { |
| float fl; // float from two 16-bit integers |
| memcpy(&fl, &buf[8], sizeof(float)); |
| fTimingCalibratedFrequency = fl; |
| } else |
| fTimingCalibratedFrequency = -1; |
| fCellCalibratedRange = ((int) (buf[10] & 0xFF)) / 100.0; // -50 ... +50 => -0.5 V ... +0.5 V |
| fCellCalibratedTemperature = (buf[10] >> 8) / 2.0; |
| ReadEEPROM(1, buf, 1024*32); |
| for (i=0 ; i<8 ; i++) |
| for (j=0 ; j<1024; j++) { |
| fCellOffset[i][j] = buf[(i*1024+j)*2]; |
| fCellGain[i][j] = buf[(i*1024+j)*2 + 1]/65535.0*0.4+0.7; |
| } |
| ReadEEPROM(2, buf, 1024*32); |
| for (i=0 ; i<8 ; i++) |
| for (j=0 ; j<1024; j++) |
| fCellOffset2[i][j] = buf[(i*1024+j)*2]; |
| } else if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8) { |
| memset(buf, 0, sizeof(buf)); |
| ReadEEPROM(0, buf, 32); |
| /* check voltage calibration method */ |
| if ((buf[2] & 0xFF) == VCALIB_METHOD_V4) // board < 9 has "1", board 9 has "2" |
| fVoltageCalibrationValid = true; |
| else { |
| fCellCalibratedRange = 0; |
| return; |
| } |
| fCellCalibratedTemperature = -100; |
| /* check timing calibration method */ |
| if ((buf[4] & 0xFF) == TCALIB_METHOD_V4) { // board < 9 has "1", board 9 has "2" |
| fTimingCalibratedFrequency = buf[6] / 1000.0; |
| } else |
| fTimingCalibratedFrequency = -1; |
| fCellCalibratedRange = ((int) (buf[2] >> 8)) / 100.0; // -50 ... +50 => -0.5 V ... +0.5 V |
| ReadEEPROM(1, buf, 1024*32); |
| for (i=0 ; i<8 ; i++) |
| for (j=0 ; j<1024; j++) { |
| fCellOffset[i][j] = buf[(i*1024+j)*2]; |
| fCellGain[i][j] = buf[(i*1024+j)*2 + 1]/65535.0*0.4+0.7; |
| } |
| ReadEEPROM(2, buf, 1024*5*4); |
| for (i=0 ; i<1 ; i++) |
| for (j=0 ; j<1024; j++) { |
| fCellOffset[i+8][j] = buf[(i*1024+j)*2]; |
| fCellGain[i+8][j] = buf[(i*1024+j)*2 + 1]/65535.0*0.4+0.7; |
| } |
| for (i=0 ; i<4 ; i++) |
| for (j=0 ; j<1024; j++) { |
| fCellOffset2[i*2][j] = buf[2*1024+(i*1024+j)*2]; |
| fCellOffset2[i*2+1][j] = buf[2*1024+(i*1024+j)*2+1]; |
| } |
| } else if (fBoardType == 6) { |
| ReadEEPROM(0, buf, 16); |
| /* check voltage calibration method */ |
| if ((buf[2] & 0xFF) == VCALIB_METHOD) |
| fVoltageCalibrationValid = true; |
| else { |
| fCellCalibratedRange = 0; |
| return; |
| } |
| /* check timing calibration method */ |
| if ((buf[4] & 0xFF) == TCALIB_METHOD) |
| fTimingCalibratedFrequency = buf[6] / 1000.0; // 0 ... 6000 => 0 ... 6 GHz |
| else |
| fTimingCalibratedFrequency = 0; |
| fCellCalibratedRange = ((int) (buf[2] >> 8)) / 100.0; // -50 ... +50 => -0.5 V ... +0.5 V |
| for (chip=0 ; chip<4 ; chip++) { |
| ReadEEPROM(1+chip, buf, 1024*32); |
| for (i=0 ; i<8 ; i++) |
| for (j=0 ; j<1024; j++) { |
| fCellOffset[i+chip*9][j] = buf[(i*1024+j)*2]; |
| fCellGain[i+chip*9][j] = buf[(i*1024+j)*2 + 1]/65535.0*0.4+0.7; |
| } |
| } |
| ReadEEPROM(5, buf, 1024*4*4); |
| for (chip=0 ; chip<4 ; chip++) |
| for (j=0 ; j<1024; j++) { |
| fCellOffset[8+chip*9][j] = buf[j*2+chip*0x0800]; |
| fCellGain[8+chip*9][j] = buf[j*2+1+chip*0x0800]/65535.0*0.4+0.7; |
| } |
| ReadEEPROM(7, buf, 1024*32); |
| for (i=0 ; i<8 ; i++) { |
| for (j=0 ; j<1024; j++) { |
| fCellOffset2[i][j] = buf[i*0x800 + j*2]; |
| fCellOffset2[i+9][j] = buf[i*0x800 + j*2+1]; |
| } |
| } |
| ReadEEPROM(8, buf, 1024*32); |
| for (i=0 ; i<8 ; i++) { |
| for (j=0 ; j<1024; j++) { |
| fCellOffset2[i+18][j] = buf[i*0x800 + j*2]; |
| fCellOffset2[i+27][j] = buf[i*0x800 + j*2+1]; |
| } |
| } |
| } else |
| return; |
| /* read timing calibration from eeprom */ |
| if (fBoardType == 9) { |
| if (fTimingCalibratedFrequency == 0) { |
| for (i=0 ; i<8 ; i++) |
| for (j=0 ; j<1024 ; j++) { |
| fCellDT[0][i][j] = 1/fNominalFrequency; |
| } |
| } else { |
| ReadEEPROM(2, buf, 1024*32); |
| for (i=0 ; i<8 ; i++) |
| for (j=0 ; j<1024; j++) { |
| fCellDT[0][i][j] = (buf[(i*1024+j)*2+1] - 1000) / 10000.0; |
| } |
| } |
| } else if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8) { |
| if (fTimingCalibratedFrequency == 0) { |
| for (i=0 ; i<1024 ; i++) |
| fCellDT[0][0][i] = 1/fNominalFrequency; |
| } else { |
| ReadEEPROM(0, buf, 1024*sizeof(short)*2); |
| for (i=0 ; i<8 ; i++) { |
| for (j=0 ; j<1024; j++) { |
| // use calibration for all channels |
| fCellDT[0][i][j] = buf[j*2+1]/10000.0; |
| } |
| } |
| } |
| } else if (fBoardType == 6) { |
| if (fTimingCalibratedFrequency == 0) { |
| for (i=0 ; i<1024 ; i++) |
| for (j=0 ; j<4 ; j++) |
| fCellDT[0][j][i] = 1/fNominalFrequency; |
| } else { |
| ReadEEPROM(6, buf, 1024*sizeof(short)*4); |
| for (i=0 ; i<1024; i++) { |
| fCellDT[0][0][i] = buf[i*2]/10000.0; |
| fCellDT[1][0][i] = buf[i*2+1]/10000.0; |
| fCellDT[2][0][i] = buf[i*2+0x800]/10000.0; |
| fCellDT[3][0][i] = buf[i*2+0x800+1]/10000.0; |
| } |
| } |
| } |
| #if 0 |
| /* Read Daniel's file */ |
| int fh = open("cal_ch2.dat", O_RDONLY); |
| float v; |
| read(fh, &v, sizeof(float)); |
| for (i=0 ; i<1024 ; i++) { |
| read(fh, &v, sizeof(float)); |
| fCellDT[0][2][(i+0) % 1024] = v; |
| } |
| close(fh); |
| fh = open("cal_ch4.dat", O_RDONLY); |
| read(fh, &v, sizeof(float)); |
| for (i=0 ; i<1024 ; i++) { |
| read(fh, &v, sizeof(float)); |
| fCellDT[0][6][(i+0)%1024] = v; |
| } |
| close(fh); |
| #endif |
| #if 0 |
| /* write timing calibration to EEPROM page 0 */ |
| double t1, t2; |
| ReadEEPROM(0, buf, sizeof(buf)); |
| for (i=0,t1=0 ; i<1024; i++) { |
| t2 = fCellT[0][i] - t1; |
| t2 = (unsigned short) (t2 * 10000 + 0.5); |
| t1 += t2 / 10000.0; |
| buf[i*2+1] = (unsigned short) t2; |
| } |
| /* write calibration method and frequency */ |
| buf[4] = TCALIB_METHOD; |
| buf[6] = (unsigned short) (fNominalFrequency * 1000 + 0.5); |
| fTimingCalibratedFrequency = buf[6] / 1000.0; |
| WriteEEPROM(0, buf, sizeof(buf)); |
| #endif |
| } |
| /*------------------------------------------------------------------*/ |
| bool DRSBoard::HasCorrectFirmware() |
| { |
| /* check for required firmware version */ |
| return (fFirmwareVersion >= fRequiredFirmwareVersion); |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::InitFPGA(void) |
| { |
| #ifdef HAVE_USB |
| if (fTransport == TR_USB2) { |
| unsigned char buffer[1]; |
| int i, status; |
| /* blink Cy7C68013A LED and issue an FPGA reset */ |
| buffer[0] = 0; // LED off |
| musb_write(fUsbInterface, 1, buffer, 1, 100); |
| Sleep(50); |
| buffer[0] = 1; // LED on |
| musb_write(fUsbInterface, 1, buffer, 1, 100); |
| /* wait until EEPROM page #0 has been read */ |
| for (i=0 ; i<100 ; i++) { |
| Read(T_STATUS, &status, REG_STATUS, 4); |
| if ((status & BIT_SERIAL_BUSY) == 0) |
| break; |
| Sleep(10); |
| } |
| } |
| #endif |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| /* Generic read function accessing VME or USB */ |
| int DRSBoard::Write(int type, unsigned int addr, void *data, int size) |
| { |
| #ifdef USE_DRS_MUTEX |
| if (!s_drsMutex) { |
| s_drsMutex = new wxMutex(); |
| assert(s_drsMutex); |
| } |
| s_drsMutex->Lock(); |
| #endif |
| if (fTransport == TR_VME) { |
| #ifdef HAVE_VME |
| unsigned int base_addr; |
| base_addr = fBaseAddress; |
| if (type == T_CTRL) |
| base_addr += PMC_CTRL_OFFSET; |
| else if (type == T_STATUS) |
| base_addr += PMC_STATUS_OFFSET; |
| else if (type == T_RAM) |
| base_addr += PMC_RAM_OFFSET; |
| if (size == 1) { |
| /* 8-bit write access */ |
| mvme_set_dmode(fVmeInterface, MVME_DMODE_D8); |
| mvme_write(fVmeInterface, base_addr + addr, static_cast < mvme_locaddr_t * >(data), size); |
| } else if (size == 2) { |
| /* 16-bit write access */ |
| mvme_set_dmode(fVmeInterface, MVME_DMODE_D16); |
| mvme_write(fVmeInterface, base_addr + addr, static_cast < mvme_locaddr_t * >(data), size); |
| } else { |
| mvme_set_dmode(fVmeInterface, MVME_DMODE_D32); |
| /* as long as no block transfer is supported, do pseudo block transfer */ |
| mvme_set_blt(fVmeInterface, MVME_BLT_NONE); |
| mvme_write(fVmeInterface, base_addr + addr, static_cast < mvme_locaddr_t * >(data), size); |
| } |
| #ifdef USE_DRS_MUTEX |
| s_drsMutex->Unlock(); |
| #endif |
| return size; |
| #endif // HAVE_VME |
| } else if (fTransport == TR_USB) { |
| #ifdef HAVE_USB |
| unsigned char buffer[64], ack; |
| unsigned int base_addr; |
| int i, j, n; |
| if (type == T_CTRL) |
| base_addr = USB_CTRL_OFFSET; |
| else if (type == T_STATUS) |
| base_addr = USB_STATUS_OFFSET; |
| else if (type == T_RAM) |
| base_addr = USB_RAM_OFFSET; |
| else |
| base_addr = 0; |
| if (type != T_RAM) { |
| /*---- register access ----*/ |
| if (size == 2) { |
| /* word swapping: first 16 bit sit at upper address */ |
| if ((addr % 4) == 0) |
| addr = addr + 2; |
| else |
| addr = addr - 2; |
| } |
| buffer[0] = USB_CMD_WRITE; |
| buffer[1] = base_addr + addr; |
| buffer[2] = size; |
| for (i = 0; i < size; i++) |
| buffer[3 + i] = *((unsigned char *) data + i); |
| /* try 10 times */ |
| ack = 0; |
| for (i = 0; i < 10; i++) { |
| n = musb_write(fUsbInterface, 2, buffer, 3 + size, USB_TIMEOUT); |
| if (n == 3 + size) { |
| for (j = 0; j < 10; j++) { |
| /* wait for acknowledge */ |
| n = musb_read(fUsbInterface, 1, &ack, 1, USB_TIMEOUT); |
| if (n == 1 && ack == 1) |
| break; |
| printf("Redo receive\n"); |
| } |
| } |
| if (ack == 1) { |
| #ifdef USE_DRS_MUTEX |
| s_drsMutex->Unlock(); |
| #endif |
| return size; |
| } |
| printf("Redo send\n"); |
| } |
| } else { |
| /*---- RAM access ----*/ |
| buffer[0] = USB_CMD_ADDR; |
| buffer[1] = base_addr + addr; |
| musb_write(fUsbInterface, 2, buffer, 2, USB_TIMEOUT); |
| /* chop buffer into 60-byte packets */ |
| for (i = 0; i <= (size - 1) / 60; i++) { |
| n = size - i * 60; |
| if (n > 60) |
| n = 60; |
| buffer[0] = USB_CMD_WRITE12; |
| buffer[1] = n; |
| for (j = 0; j < n; j++) |
| buffer[2 + j] = *((unsigned char *) data + j + i * 60); |
| musb_write(fUsbInterface, 2, buffer, 2 + n, USB_TIMEOUT); |
| for (j = 0; j < 10; j++) { |
| /* wait for acknowledge */ |
| n = musb_read(fUsbInterface, 1, &ack, 1, USB_TIMEOUT); |
| if (n == 1 && ack == 1) |
| break; |
| printf("Redo receive acknowledge\n"); |
| } |
| } |
| #ifdef USE_DRS_MUTEX |
| s_drsMutex->Unlock(); |
| #endif |
| return size; |
| } |
| #endif // HAVE_USB |
| } else if (fTransport == TR_USB2) { |
| #ifdef HAVE_USB |
| unsigned int base_addr; |
| int i; |
| if (usb2_buffer == NULL) |
| usb2_buffer = (unsigned char *) malloc(USB2_BUFFER_SIZE); |
| assert(usb2_buffer); |
| /* only accept even address and number of bytes */ |
| assert(addr % 2 == 0); |
| assert(size % 2 == 0); |
| /* check for maximum size */ |
| assert(size <= USB2_BUFFER_SIZE - 10); |
| if (type == T_CTRL) |
| base_addr = USB2_CTRL_OFFSET; |
| else if (type == T_STATUS) |
| base_addr = USB2_STATUS_OFFSET; |
| else if (type == T_FIFO) |
| base_addr = USB2_FIFO_OFFSET; |
| else if (type == T_RAM) |
| base_addr = USB2_RAM_OFFSET; |
| else |
| base_addr = 0; |
| if (type != T_RAM && size == 2) { |
| /* word swapping: first 16 bit sit at upper address */ |
| if ((addr % 4) == 0) |
| addr = addr + 2; |
| else |
| addr = addr - 2; |
| } |
| addr += base_addr; |
| usb2_buffer[0] = USB2_CMD_WRITE; |
| usb2_buffer[1] = 0; |
| usb2_buffer[2] = (addr >> 0) & 0xFF; |
| usb2_buffer[3] = (addr >> 8) & 0xFF; |
| usb2_buffer[4] = (addr >> 16) & 0xFF; |
| usb2_buffer[5] = (addr >> 24) & 0xFF; |
| usb2_buffer[6] = (size >> 0) & 0xFF; |
| usb2_buffer[7] = (size >> 8) & 0xFF; |
| usb2_buffer[8] = (size >> 16) & 0xFF; |
| usb2_buffer[9] = (size >> 24) & 0xFF; |
| for (i = 0; i < size; i++) |
| usb2_buffer[10 + i] = *((unsigned char *) data + i); |
| i = musb_write(fUsbInterface, 4, usb2_buffer, 10 + size, USB_TIMEOUT); |
| if (i != 10 + size) |
| printf("musb_write error: %d\n", i); |
| #ifdef USE_DRS_MUTEX |
| s_drsMutex->Unlock(); |
| #endif |
| return i; |
| #endif // HAVE_USB |
| } |
| #ifdef USE_DRS_MUTEX |
| s_drsMutex->Unlock(); |
| #endif |
| return 0; |
| } |
| /*------------------------------------------------------------------*/ |
| /* Generic read function accessing VME or USB */ |
| int DRSBoard::Read(int type, void *data, unsigned int addr, int size) |
| { |
| #ifdef USE_DRS_MUTEX |
| if (!s_drsMutex) { |
| s_drsMutex = new wxMutex(); |
| assert(s_drsMutex); |
| } |
| s_drsMutex->Lock(); |
| #endif |
| memset(data, 0, size); |
| if (fTransport == TR_VME) { |
| #ifdef HAVE_VME |
| unsigned int base_addr; |
| int n, i; |
| base_addr = fBaseAddress; |
| if (type == T_CTRL) |
| base_addr += PMC_CTRL_OFFSET; |
| else if (type == T_STATUS) |
| base_addr += PMC_STATUS_OFFSET; |
| else if (type == T_RAM) |
| base_addr += PMC_RAM_OFFSET; |
| else if (type == T_FIFO) |
| base_addr += PMC_FIFO_OFFSET; |
| mvme_set_dmode(fVmeInterface, MVME_DMODE_D32); |
| n = 0; |
| if (size == 1) { |
| /* 8-bit read access */ |
| mvme_set_dmode(fVmeInterface, MVME_DMODE_D8); |
| n = mvme_read(fVmeInterface, static_cast < mvme_locaddr_t * >(data), base_addr + addr, size); |
| } else if (size == 2) { |
| /* 16-bit read access */ |
| mvme_set_dmode(fVmeInterface, MVME_DMODE_D16); |
| n = mvme_read(fVmeInterface, static_cast < mvme_locaddr_t * >(data), base_addr + addr, size); |
| } else { |
| mvme_set_dmode(fVmeInterface, MVME_DMODE_D32); |
| //mvme_set_blt(fVmeInterface, MVME_BLT_NONE); // pseudo block transfer |
| mvme_set_blt(fVmeInterface, MVME_BLT_2EVME); // 2eVME if implemented |
| n = mvme_read(fVmeInterface, static_cast < mvme_locaddr_t * >(data), base_addr + addr, size); |
| while (n != size) { |
| printf("Only read %d out of %d, retry with %d: ", n, size, size - n); |
| i = mvme_read(fVmeInterface, static_cast < mvme_locaddr_t * >(data) + n / 4, base_addr + addr + n, |
| size - n); |
| printf("read %d\n", i); |
| if (i == 0) { |
| printf("Error reading VME\n"); |
| return n; |
| } |
| n += i; |
| } |
| //for (i = 0; i < size; i += 4) |
| // mvme_read(fVmeInterface, (mvme_locaddr_t *)((char *)data+i), base_addr + addr+i, 4); |
| } |
| #ifdef USE_DRS_MUTEX |
| s_drsMutex->Unlock(); |
| #endif |
| return n; |
| #endif // HAVE_VME |
| } else if (fTransport == TR_USB) { |
| #ifdef HAVE_USB |
| unsigned char buffer[64]; |
| unsigned int base_addr; |
| int i, j, ret, n; |
| if (type == T_CTRL) |
| base_addr = USB_CTRL_OFFSET; |
| else if (type == T_STATUS) |
| base_addr = USB_STATUS_OFFSET; |
| else if (type == T_RAM) |
| base_addr = USB_RAM_OFFSET; |
| else |
| assert(0); // FIFO not implemented |
| if (type != T_RAM) { |
| /*---- register access ----*/ |
| if (size == 2) { |
| /* word swapping: first 16 bit sit at uppder address */ |
| if ((addr % 4) == 0) |
| addr = addr + 2; |
| else |
| addr = addr - 2; |
| } |
| buffer[0] = USB_CMD_READ; |
| buffer[1] = base_addr + addr; |
| buffer[2] = size; |
| musb_write(fUsbInterface, 2, buffer, 2 + size, USB_TIMEOUT); |
| i = musb_read(fUsbInterface, 1, data, size, USB_TIMEOUT); |
| #ifdef USE_DRS_MUTEX |
| s_drsMutex->Unlock(); |
| #endif |
| if (i != size) |
| return 0; |
| return size; |
| } else { |
| /*---- RAM access ----*/ |
| /* in RAM mode, only the 2048-byte page can be selected */ |
| buffer[0] = USB_CMD_ADDR; |
| buffer[1] = base_addr + (addr >> 11); |
| musb_write(fUsbInterface, 2, buffer, 2, USB_TIMEOUT); |
| /* receive data in 60-byte packets */ |
| for (i = 0; i <= (size - 1) / 60; i++) { |
| n = size - i * 60; |
| if (n > 60) |
| n = 60; |
| buffer[0] = USB_CMD_READ12; |
| buffer[1] = n; |
| musb_write(fUsbInterface, 2, buffer, 2, USB_TIMEOUT); |
| ret = musb_read(fUsbInterface, 1, buffer, n, USB_TIMEOUT); |
| if (ret != n) { |
| /* try again */ |
| ret = musb_read(fUsbInterface, 1, buffer, n, USB_TIMEOUT); |
| if (ret != n) { |
| #ifdef USE_DRS_MUTEX |
| s_drsMutex->Unlock(); |
| #endif |
| return 0; |
| } |
| } |
| for (j = 0; j < ret; j++) |
| *((unsigned char *) data + j + i * 60) = buffer[j]; |
| } |
| #ifdef USE_DRS_MUTEX |
| s_drsMutex->Unlock(); |
| #endif |
| return size; |
| } |
| #endif // HAVE_USB |
| } else if (fTransport == TR_USB2) { |
| #ifdef HAVE_USB |
| unsigned char buffer[10]; |
| unsigned int base_addr; |
| int i; |
| /* only accept even address and number of bytes */ |
| assert(addr % 2 == 0); |
| assert(size % 2 == 0); |
| /* check for maximum size */ |
| assert(size <= USB2_BUFFER_SIZE - 10); |
| if (type == T_CTRL) |
| base_addr = USB2_CTRL_OFFSET; |
| else if (type == T_STATUS) |
| base_addr = USB2_STATUS_OFFSET; |
| else if (type == T_FIFO) |
| base_addr = USB2_FIFO_OFFSET; |
| else if (type == T_RAM) |
| base_addr = USB2_RAM_OFFSET; |
| else |
| base_addr = 0; |
| if (type != T_RAM && size == 2) { |
| /* word swapping: first 16 bit sit at upper address */ |
| if ((addr % 4) == 0) |
| addr = addr + 2; |
| else |
| addr = addr - 2; |
| } |
| addr += base_addr; |
| buffer[0] = USB2_CMD_READ; |
| buffer[1] = 0; |
| buffer[2] = (addr >> 0) & 0xFF; |
| buffer[3] = (addr >> 8) & 0xFF; |
| buffer[4] = (addr >> 16) & 0xFF; |
| buffer[5] = (addr >> 24) & 0xFF; |
| buffer[6] = (size >> 0) & 0xFF; |
| buffer[7] = (size >> 8) & 0xFF; |
| buffer[8] = (size >> 16) & 0xFF; |
| buffer[9] = (size >> 24) & 0xFF; |
| i = musb_write(fUsbInterface, 4, buffer, 10, USB_TIMEOUT); |
| if (i != 10) |
| printf("musb_read error %d\n", i); |
| i = musb_read(fUsbInterface, 8, data, size, USB_TIMEOUT); |
| #ifdef USE_DRS_MUTEX |
| s_drsMutex->Unlock(); |
| #endif |
| return i; |
| #endif // HAVE_USB |
| } |
| #ifdef USE_DRS_MUTEX |
| s_drsMutex->Unlock(); |
| #endif |
| return 0; |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::SetLED(int state) |
| { |
| // Set LED state |
| if (state) |
| fCtrlBits |= BIT_LED; |
| else |
| fCtrlBits &= ~BIT_LED; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetChannelConfig(int firstChannel, int lastChannel, int nConfigChannels) |
| { |
| unsigned short d; |
| if (lastChannel < 0 || lastChannel > 10) { |
| printf("Invalid number of channels: %d (must be between 0 and 10)\n", lastChannel); |
| return 0; |
| } |
| // Set number of channels |
| if (fDRSType == 2) { |
| // register must contain last channel to read out starting from 9 |
| d = 9 - lastChannel; |
| Write(T_CTRL, REG_CHANNEL_CONFIG, &d, 2); |
| } else if (fDRSType == 3) { |
| // upper four bits of register must contain last channel to read out starting from 9 |
| d = (firstChannel << 4) | lastChannel; |
| Write(T_CTRL, REG_CHANNEL_MODE, &d, 2); |
| // set bit pattern for write shift register |
| switch (nConfigChannels) { |
| case 1: |
| d = 0x001; |
| break; |
| case 2: |
| d = 0x041; |
| break; |
| case 3: |
| d = 0x111; |
| break; |
| case 4: |
| d = 0x249; |
| break; |
| case 6: |
| d = 0x555; |
| break; |
| case 12: |
| d = 0xFFF; |
| break; |
| default: |
| printf("Invalid channel configuration\n"); |
| return 0; |
| } |
| Write(T_CTRL, REG_CHANNEL_CONFIG, &d, 2); |
| } else if (fDRSType == 4) { |
| int oldMultiBuffer = fMultiBuffer; |
| // make sure FPGA state machine is idle |
| if (fHasMultiBuffer) { |
| SetMultiBuffer(0); |
| if (IsBusy()) { |
| SoftTrigger(); |
| while (IsBusy()); |
| } |
| } |
| if (fBoardType == 6) { |
| // determined channel readout mode A/C[even/odd], B/D[even/odd] or A/B/C/D |
| fReadoutChannelConfig = firstChannel; |
| Read(T_CTRL, &d, REG_CHANNEL_MODE, 2); |
| d = (d & 0xFF00) | firstChannel; // keep higher 8 bits which are ADClkPhase |
| Write(T_CTRL, REG_CHANNEL_MODE, &d, 2); |
| } else { |
| // upper four bits of register must contain last channel to read out starting from 9 |
| Read(T_CTRL, &d, REG_CHANNEL_MODE, 2); |
| d = (d & 0xFF00) | (firstChannel << 4) | lastChannel; // keep higher 8 bits which are ADClkPhase |
| Write(T_CTRL, REG_CHANNEL_MODE, &d, 2); |
| } |
| // set bit pattern for write shift register |
| fChannelConfig = 0; |
| switch (nConfigChannels) { |
| case 1: |
| fChannelConfig = 0x01; |
| fChannelCascading = 8; |
| break; |
| case 2: |
| fChannelConfig = 0x11; |
| fChannelCascading = 4; |
| break; |
| case 4: |
| fChannelConfig = 0x55; |
| fChannelCascading = 2; |
| break; |
| case 8: |
| fChannelConfig = 0xFF; |
| fChannelCascading = 1; |
| break; |
| default: |
| printf("Invalid channel configuration\n"); |
| return 0; |
| } |
| d = fChannelConfig | (fDominoMode << 8) | (1 << 9) | (fWSRLoop << 10) | (0xF8 << 8); |
| Write(T_CTRL, REG_CHANNEL_CONFIG, &d, 2); |
| fChannelDepth = fChannelCascading * (fDecimation ? kNumberOfBins/2 : kNumberOfBins); |
| if (fHasMultiBuffer && oldMultiBuffer) { |
| Reinit(); // set WP=0 |
| SetMultiBuffer(oldMultiBuffer); |
| SetMultiBufferRP(0); |
| } |
| } |
| if (fBoardType == 6) { |
| if (fReadoutChannelConfig == 7) |
| fNumberOfReadoutChannels = 9; |
| else |
| fNumberOfReadoutChannels = 5; |
| } else { |
| fNumberOfReadoutChannels = lastChannel - firstChannel + 1; |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::SetNumberOfChannels(int nChannels) |
| { |
| SetChannelConfig(0, nChannels - 1, 12); |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::SetADCClkPhase(int phase, bool invert) |
| { |
| unsigned short d = 0; |
| /* Set the clock phase of the ADC via the variable phase shift |
| in the Xilinx DCM. One unit is equal to the clock period / 256, |
| so at 30 MHz this is about 130ps. The possible range at 30 MHz |
| is -87 ... +87 */ |
| // keep lower 8 bits which are the channel mode |
| Read(T_CTRL, &d, REG_ADCCLK_PHASE, 2); |
| d = (d & 0x00FF) | (phase << 8); |
| Write(T_CTRL, REG_ADCCLK_PHASE, &d, 2); |
| if (invert) |
| fCtrlBits |= BIT_ADCCLK_INVERT; |
| else |
| fCtrlBits &= ~BIT_ADCCLK_INVERT; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| fADCClkPhase = phase; |
| fADCClkInvert = invert; |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::SetWarmup(unsigned int microseconds) |
| { |
| /* Set the "warmup" time. When starting the domino wave, the DRS4 |
| chip together with its power supply need some time to stabilize |
| before high resolution data can be taken (jumping baseline |
| problem). This sets the time in ticks of 900ns before triggers |
| are accepted */ |
| unsigned short ticks; |
| if (microseconds == 0) |
| ticks = 0; |
| else |
| ticks = (unsigned short) (microseconds / 0.9 + 0.5) - 1; |
| Write(T_CTRL, REG_WARMUP, &ticks, 2); |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::SetCooldown(unsigned int microseconds) |
| { |
| /* Set the "cooldown" time. When stopping the domino wave, the |
| power supply needs some time to stabilize before high resolution |
| data can read out (slanted baseline problem). This sets the |
| time in ticks of 900 ns before the readout is started */ |
| unsigned short ticks; |
| ticks = (unsigned short) (microseconds / 0.9 + 0.5) - 1; |
| Write(T_CTRL, REG_COOLDOWN, &ticks, 2); |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetDAC(unsigned char channel, double value) |
| { |
| // Set DAC value |
| unsigned short d; |
| /* normalize to 2.5V for 16 bit */ |
| if (value < 0) |
| value = 0; |
| if (value > 2.5) |
| value = 2.5; |
| d = static_cast < unsigned short >(value / 2.5 * 0xFFFF + 0.5); |
| Write(T_CTRL, REG_DAC_OFS + (channel * 2), &d, 2); |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::ReadDAC(unsigned char channel, double *value) |
| { |
| // Readback DAC value from control register |
| unsigned char buffer[2]; |
| /* map 0->1, 1->0, 2->3, 3->2, etc. */ |
| //ofs = channel + 1 - 2*(channel % 2); |
| Read(T_CTRL, buffer, REG_DAC_OFS + (channel * 2), 2); |
| /* normalize to 2.5V for 16 bit */ |
| *value = 2.5 * (buffer[0] + (buffer[1] << 8)) / 0xFFFF; |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::GetRegulationDAC(double *value) |
| { |
| // Get DAC value from status register (-> freq. regulation) |
| unsigned char buffer[2]; |
| if (fBoardType == 1) |
| Read(T_STATUS, buffer, REG_RDAC3, 2); |
| else if (fBoardType == 2 || fBoardType == 3 || fBoardType == 4) |
| Read(T_STATUS, buffer, REG_RDAC1, 2); |
| else |
| memset(buffer, 0, sizeof(buffer)); |
| /* normalize to 2.5V for 16 bit */ |
| *value = 2.5 * (buffer[0] + (buffer[1] << 8)) / 0xFFFF; |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::StartDomino() |
| { |
| // Start domino sampling |
| fCtrlBits |= BIT_START_TRIG; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| fCtrlBits &= ~BIT_START_TRIG; |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::Reinit() |
| { |
| // Stop domino sampling |
| // reset readout state machine |
| // reset FIFO counters |
| fCtrlBits |= BIT_REINIT_TRIG; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| fCtrlBits &= ~BIT_REINIT_TRIG; |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::Init() |
| { |
| // Init FPGA on USB2 board |
| InitFPGA(); |
| // Turn off multi-buffer mode to avoid immediate startup |
| SetMultiBuffer(0); |
| // Reinitialize |
| fCtrlBits |= BIT_REINIT_TRIG; // reset readout state machine |
| if (fDRSType == 2) |
| fCtrlBits &= ~BIT_FREQ_AUTO_ADJ; // turn auto. freq regul. off |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| fCtrlBits &= ~BIT_REINIT_TRIG; |
| if (fBoardType == 1) { |
| // set max. domino speed |
| SetDAC(fDAC_DRA, 2.5); |
| SetDAC(fDAC_DSA, 2.5); |
| SetDAC(fDAC_DRB, 2.5); |
| SetDAC(fDAC_DSB, 2.5); |
| // set readout offset |
| SetDAC(fDAC_COFSA, 0.9); |
| SetDAC(fDAC_COFSB, 0.9); |
| SetDAC(fDAC_TLEVEL, 1.7); |
| } else if (fBoardType == 2 || fBoardType == 3) { |
| // set max. domino speed |
| SetDAC(fDAC_DSA, 2.5); |
| SetDAC(fDAC_DSB, 2.5); |
| // set readout offset |
| SetDAC(fDAC_COFS, 0.9); |
| SetDAC(fDAC_TLEVEL, 1.7); |
| SetDAC(fDAC_ADCOFS, 1.7); // 1.7 for DC coupling, 1.25 for AC |
| SetDAC(fDAC_CLKOFS, 1); |
| } else if (fBoardType == 4) { |
| // set max. domino speed |
| SetDAC(fDAC_DSA, 2.5); |
| SetDAC(fDAC_DSB, 2.5); |
| // set readout offset |
| SetDAC(fDAC_ROFS_1, 1.25); // LVDS level |
| //SetDAC(fDAC_ROFS_2, 0.85); // linear range 0.1V ... 1.1V |
| SetDAC(fDAC_ROFS_2, 1.05); // differential input from Lecce splitter |
| SetDAC(fDAC_ADCOFS, 1.25); |
| SetDAC(fDAC_ACALIB, 0.5); |
| SetDAC(fDAC_INOFS, 0.6); |
| SetDAC(fDAC_BIAS, 0.70); // a bit above the internal bias of 0.68V |
| } else if (fBoardType == 5) { |
| // DRS4 USB Evaluation Board 1.1 + 2.0 |
| // set max. domino speed |
| SetDAC(fDAC_DSA, 2.5); |
| // set readout offset |
| fROFS = 1.6; // differential input range -0.5V ... +0.5V |
| fRange = 0; |
| SetDAC(fDAC_ROFS_1, fROFS); |
| // set common mode offset |
| fCommonMode = 0.8; // 0.8V +- 0.5V inside NMOS range |
| SetDAC(fDAC_CMOFS, fCommonMode); |
| // calibration voltage |
| SetDAC(fDAC_CALP, fCommonMode); |
| SetDAC(fDAC_CALN, fCommonMode); |
| // OUT- offset |
| SetDAC(fDAC_ONOFS, 1.25); |
| SetDAC(fDAC_BIAS, 0.70); |
| } else if (fBoardType == 6) { |
| // DRS4 Mezzanine Board 1.0 |
| // set readout offset |
| fROFS = 1.6; // differential input range -0.5V ... +0.5V |
| fRange = 0; |
| SetDAC(fDAC_ROFS_1, fROFS); |
| // set common mode offset |
| fCommonMode = 0.8; // 0.8V +- 0.5V inside NMOS range |
| SetDAC(fDAC_CMOFSP, fCommonMode); |
| SetDAC(fDAC_CMOFSN, fCommonMode); |
| // calibration voltage |
| SetDAC(fDAC_CALN, fCommonMode); |
| SetDAC(fDAC_CALP, fCommonMode); |
| // OUT- offset |
| SetDAC(fDAC_ONOFS, 1.25); |
| SetDAC(fDAC_BIAS, 0.70); |
| } else if (fBoardType == 7) { |
| // DRS4 USB Evaluation 3.0 |
| // set max. domino speed |
| SetDAC(fDAC_DSA, 2.5); |
| // set readout offset |
| fROFS = 1.6; // differential input range -0.5V ... +0.5V |
| fRange = 0; |
| SetDAC(fDAC_ROFS_1, fROFS); |
| // set common mode for THS4508 |
| SetDAC(fDAC_CMOFS, 2.4); |
| // calibration voltage |
| fCommonMode = 0.8; // 0.8V +- 0.5V inside NMOS range |
| SetDAC(fDAC_CALP, fCommonMode); |
| SetDAC(fDAC_CALN, fCommonMode); |
| // OUT- offset |
| SetDAC(fDAC_ONOFS, 1.25); |
| SetDAC(fDAC_BIAS, 0.70); |
| } else if (fBoardType == 8 || fBoardType == 9) { |
| // DRS4 USB Evaluation 4.0 |
| // set readout offset |
| fROFS = 1.6; // differential input range -0.5V ... +0.5V |
| fRange = 0; |
| SetDAC(fDAC_ROFS_1, fROFS); |
| // calibration voltage |
| fCommonMode = 0.8; // 0.8V +- 0.5V inside NMOS range |
| SetDAC(fDAC_CALP, fCommonMode); |
| SetDAC(fDAC_CALN, fCommonMode); |
| SetDAC(fDAC_BIAS, 0.70); |
| } |
| /* set default number of channels per chip */ |
| if (fDRSType == 4) { |
| if (fTransport == TR_USB2) |
| SetChannelConfig(0, fNumberOfReadoutChannels - 1, 8); |
| else |
| SetChannelConfig(7, fNumberOfReadoutChannels - 1, 8); |
| } else |
| SetChannelConfig(0, fNumberOfReadoutChannels - 1, 12); |
| // set ADC clock phase |
| if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) { |
| fADCClkPhase = 0; |
| fADCClkInvert = 0; |
| } else if (fBoardType == 6) { |
| fADCClkPhase = 65; |
| fADCClkInvert = 0; |
| } |
| // default settings |
| fMultiBuffer = 0; |
| fNMultiBuffer = 0; |
| fDominoMode = 1; |
| fReadoutMode = 1; |
| fReadPointer = 0; |
| fTriggerEnable1 = 0; |
| fTriggerEnable2 = 0; |
| fTriggerSource = 0; |
| fTriggerDelay = 0; |
| fTriggerDelayNs = 0; |
| fSyncDelay = 0; |
| fNominalFrequency = 1; |
| fDominoActive = 1; |
| // load calibration from EEPROM |
| ReadCalibration(); |
| // get some settings from hardware |
| fRange = GetCalibratedInputRange(); |
| if (fRange < 0 || fRange > 0.5) |
| fRange = 0; |
| fNominalFrequency = GetCalibratedFrequency(); |
| if (fNominalFrequency < 0.1 || fNominalFrequency > 6) |
| fNominalFrequency = 1; |
| if (fHasMultiBuffer) { |
| SetMultiBuffer(fMultiBuffer); |
| SetMultiBufferRP(fReadPointer); |
| } |
| SetDominoMode(fDominoMode); |
| SetReadoutMode(fReadoutMode); |
| EnableTrigger(fTriggerEnable1, fTriggerEnable2); |
| SetTriggerSource(fTriggerSource); |
| SetTriggerDelayPercent(0); |
| SetSyncDelay(fSyncDelay); |
| SetDominoActive(fDominoActive); |
| SetFrequency(fNominalFrequency, true); |
| SetInputRange(fRange); |
| if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) |
| SelectClockSource(0); // FPGA clock |
| if (fBoardType == 6) { |
| SetADCClkPhase(fADCClkPhase, fADCClkInvert); |
| SetWarmup(0); |
| SetCooldown(100); |
| SetDecimation(0); |
| } |
| // disable calibration signals |
| EnableAcal(0, 0); |
| SetCalibTiming(0, 0); |
| EnableTcal(0); |
| // got to idle state |
| Reinit(); |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetDominoMode(unsigned char mode) |
| { |
| // Set domino mode |
| // mode == 0: single sweep |
| // mode == 1: run continously |
| // |
| fDominoMode = mode; |
| if (fDRSType == 4) { |
| unsigned short d; |
| Read(T_CTRL, &d, REG_CONFIG, 2); |
| fChannelConfig = d & 0xFF; |
| d = fChannelConfig | (fDominoMode << 8) | (1 << 9) | (fWSRLoop << 10) | (0xF8 << 8); |
| Write(T_CTRL, REG_CONFIG, &d, 2); |
| } else { |
| if (mode) |
| fCtrlBits |= BIT_DMODE; |
| else |
| fCtrlBits &= ~BIT_DMODE; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetDominoActive(unsigned char mode) |
| { |
| // Set domino activity |
| // mode == 0: stop during readout |
| // mode == 1: keep domino wave running |
| // |
| fDominoActive = mode; |
| if (mode) |
| fCtrlBits |= BIT_DACTIVE; |
| else |
| fCtrlBits &= ~BIT_DACTIVE; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetReadoutMode(unsigned char mode) |
| { |
| // Set readout mode |
| // mode == 0: start from first bin |
| // mode == 1: start from domino stop |
| // |
| fReadoutMode = mode; |
| if (mode) |
| fCtrlBits |= BIT_READOUT_MODE; |
| else |
| fCtrlBits &= ~BIT_READOUT_MODE; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SoftTrigger(void) |
| { |
| // Send a software trigger |
| fCtrlBits |= BIT_SOFT_TRIG; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| fCtrlBits &= ~BIT_SOFT_TRIG; |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::EnableTrigger(int flag1, int flag2) |
| { |
| // Enable external trigger |
| fTriggerEnable1 = flag1; |
| fTriggerEnable2 = flag2; |
| if (flag1) |
| fCtrlBits |= BIT_ENABLE_TRIGGER1; |
| else |
| fCtrlBits &= ~BIT_ENABLE_TRIGGER1; |
| if (flag2) |
| fCtrlBits |= BIT_ENABLE_TRIGGER2; |
| else |
| fCtrlBits &= ~BIT_ENABLE_TRIGGER2; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetDelayedTrigger(int flag) |
| { |
| // Select delayed trigger from trigger bus |
| if (flag) |
| fCtrlBits |= BIT_TRIGGER_DELAYED; |
| else |
| fCtrlBits &= ~BIT_TRIGGER_DELAYED; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetTriggerPolarity(bool negative) |
| { |
| if (fBoardType == 5 || fBoardType == 7) { |
| fTcalLevel = negative; |
| if (negative) |
| fCtrlBits |= BIT_NEG_TRIGGER; |
| else |
| fCtrlBits &= ~BIT_NEG_TRIGGER; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| return 1; |
| } else if (fBoardType == 8 || fBoardType == 9) { |
| fTcalLevel = negative; |
| if (negative) |
| fCtrlBits |= BIT_NEG_TRIGGER; |
| else |
| fCtrlBits &= ~BIT_NEG_TRIGGER; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| return 1; |
| } |
| return 0; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetTriggerLevel(double voltage) |
| { |
| if (fBoardType == 5 || fBoardType == 7) { |
| return SetDAC(fDAC_TLEVEL, voltage/2 + 0.8); |
| } else if (fBoardType == 8 || fBoardType == 9) { |
| SetIndividualTriggerLevel(0, voltage); |
| SetIndividualTriggerLevel(1, voltage); |
| SetIndividualTriggerLevel(2, voltage); |
| SetIndividualTriggerLevel(3, voltage); |
| return 1; |
| } |
| return 0; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetIndividualTriggerLevel(int channel, double voltage) |
| { |
| if (fBoardType == 8 || fBoardType == 9) { |
| switch (channel) { |
| case 0: SetDAC(fDAC_TLEVEL1, voltage/2 + 0.8); break; |
| case 1: SetDAC(fDAC_TLEVEL2, voltage/2 + 0.8); break; |
| case 2: SetDAC(fDAC_TLEVEL3, voltage/2 + 0.8); break; |
| case 3: SetDAC(fDAC_TLEVEL4, voltage/2 + 0.8); break; |
| default: return -1; |
| } |
| } |
| return 0; |
| } |
| /*------------------------------------------------------------------*/ |
| #define LUT_DELAY_S3_8 6.2 // Spartan 3 Octal LUTs 2 GSPS |
| #define LUT_DELAY_S3_4 2.1 // Spartan 3 Quad LUTs |
| #define LUT_DELAY_V2_8 4.6 // Virtex PRO II Octal LUTs |
| #define LUT_DELAY_V2_4 2.3 // Virtex PRO II Quad LUTs |
| int DRSBoard::SetTriggerDelayPercent(int delay) |
| /* set trigger delay in percent 0..100 */ |
| { |
| short ticks, reg; |
| fTriggerDelay = delay; |
| if (fBoardType == 5 || fBoardType == 6 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) { |
| // convert delay (0..100) into ticks |
| ticks = (unsigned short) (delay/100.0*255+0.5); |
| if (ticks > 255) |
| ticks = 255; |
| if (ticks < 0) |
| ticks = 0; |
| // convert delay into ns |
| if (fBoardType == 7 || fBoardType == 8 || fBoardType == 9) { |
| if (fFirmwareVersion >= 17147) |
| fTriggerDelayNs = ticks * LUT_DELAY_S3_8; |
| else |
| fTriggerDelayNs = ticks * LUT_DELAY_S3_4; |
| } else { |
| if (fFirmwareVersion >= 17382) |
| fTriggerDelayNs = ticks * LUT_DELAY_V2_8; |
| else |
| fTriggerDelayNs = ticks * LUT_DELAY_V2_4; |
| } |
| // adjust for fixed delay, measured and approximated experimentally |
| fTriggerDelayNs += 23.5 + 28.2/fNominalFrequency; |
| Read(T_CTRL, ®, REG_TRG_DELAY, 2); |
| reg = (reg & 0xFF00) | ticks; |
| Write(T_CTRL, REG_TRG_DELAY, &ticks, 2); |
| return 1; |
| } |
| return 0; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetTriggerDelayNs(int delay) |
| /* set trigger delay in nanoseconds */ |
| { |
| short ticks, reg; |
| fTriggerDelayNs = delay; |
| if (fBoardType == 5 || fBoardType == 6 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) { |
| // convert delay in ns into ticks |
| if (fBoardType == 7 || fBoardType == 8 || fBoardType == 9) { |
| if (fFirmwareVersion >= 17147) |
| ticks = (short int)(delay / LUT_DELAY_S3_8 + 0.5); |
| else |
| ticks = (short int)(delay / LUT_DELAY_S3_4 + 0.5); |
| } else { |
| if (fFirmwareVersion >= 17382) |
| ticks = (short int)(delay / LUT_DELAY_V2_8 + 0.5); |
| else |
| ticks = (short int)(delay / LUT_DELAY_V2_4 + 0.5); |
| } |
| if (ticks > 255) |
| ticks = 255; |
| if (ticks < 0) |
| ticks = 0; |
| fTriggerDelay = ticks / 255 * 100; |
| Read(T_CTRL, ®, REG_TRG_DELAY, 2); |
| reg = (reg & 0xFF00) | ticks; |
| Write(T_CTRL, REG_TRG_DELAY, &ticks, 2); |
| return 1; |
| } |
| return 0; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetSyncDelay(int ticks) |
| { |
| short int reg; |
| if (fBoardType == 5 || fBoardType == 6 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) { |
| Read(T_CTRL, ®, REG_TRG_DELAY, 2); |
| reg = (reg & 0xFF) | (ticks << 8); |
| Write(T_CTRL, REG_TRG_DELAY, ®, 2); |
| return 1; |
| } |
| return 0; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetTriggerSource(int source) |
| { |
| short int reg; |
| fTriggerSource = source; |
| if (fBoardType == 5 || fBoardType == 7) { |
| // Set trigger source |
| // 0=CH1, 1=CH2, 2=CH3, 3=CH4 |
| if (source & 1) |
| fCtrlBits |= BIT_TR_SOURCE1; |
| else |
| fCtrlBits &= ~BIT_TR_SOURCE1; |
| if (source & 2) |
| fCtrlBits |= BIT_TR_SOURCE2; |
| else |
| fCtrlBits &= ~BIT_TR_SOURCE2; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| } else if (fBoardType == 8 || fBoardType == 9) { |
| // Set trigger configuration |
| // OR Bit0=CH1, Bit1=CH2, Bit2=CH3, Bit3=CH4, Bit4=EXT |
| // AND Bit8=CH1, Bit9=CH2, Bit10=CH3, Bit11=CH4, Bit12=EXT |
| // TRANSP Bit15 |
| reg = (unsigned short) source; |
| Write(T_CTRL, REG_TRG_CONFIG, ®, 2); |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetDelayedStart(int flag) |
| { |
| // Enable external trigger |
| fDelayedStart = flag; |
| if (flag) |
| fCtrlBits |= BIT_DELAYED_START; |
| else |
| fCtrlBits &= ~BIT_DELAYED_START; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetTranspMode(int flag) |
| { |
| // Enable/disable transparent mode |
| fTranspMode = flag; |
| if (flag) |
| fCtrlBits |= BIT_TRANSP_MODE; |
| else |
| fCtrlBits &= ~BIT_TRANSP_MODE; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetStandbyMode(int flag) |
| { |
| // Enable/disable standby mode |
| fTranspMode = flag; |
| if (flag) |
| fCtrlBits |= BIT_STANDBY_MODE; |
| else |
| fCtrlBits &= ~BIT_STANDBY_MODE; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetDecimation(int flag) |
| { |
| // Drop every odd sample |
| fDecimation = flag; |
| if (flag) |
| fCtrlBits |= BIT_DECIMATION; |
| else |
| fCtrlBits &= ~BIT_DECIMATION; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| // Calculate channel depth |
| fChannelDepth = fChannelCascading * (fDecimation ? kNumberOfBins/2 : kNumberOfBins); |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::IsBusy() |
| { |
| // Get running flag |
| unsigned int status; |
| Read(T_STATUS, &status, REG_STATUS, 4); |
| return (status & BIT_RUNNING) > 0; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::IsEventAvailable() |
| { |
| if (!fMultiBuffer) |
| return !IsBusy(); |
| return GetMultiBufferWP() != fReadPointer; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::IsPLLLocked() |
| { |
| // Get running flag |
| unsigned int status; |
| Read(T_STATUS, &status, REG_STATUS, 4); |
| if (GetBoardType() == 6) |
| return ((status >> 1) & 0x0F) == 0x0F; |
| return (status & BIT_PLL_LOCKED0) > 0; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::IsLMKLocked() |
| { |
| // Get running flag |
| unsigned int status; |
| Read(T_STATUS, &status, REG_STATUS, 4); |
| if (GetBoardType() == 6) |
| return (status & BIT_LMK_LOCKED) > 0; |
| return 0; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::IsNewFreq(unsigned char chipIndex) |
| { |
| unsigned int status; |
| Read(T_STATUS, &status, REG_STATUS, 4); |
| if (chipIndex == 0) |
| return (status & BIT_NEW_FREQ1) > 0; |
| return (status & BIT_NEW_FREQ2) > 0; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::ReadFrequency(unsigned char chipIndex, double *f) |
| { |
| if (fDRSType == 4) { |
| if (fBoardType == 6) { |
| *f = fNominalFrequency; |
| return 1; |
| } |
| unsigned short ticks; |
| Read(T_CTRL, &ticks, REG_FREQ_SET, 2); |
| ticks += 2; |
| /* convert rounded ticks back to frequency */ |
| if (ticks > 2) |
| *f = 1.024 / ticks * fRefClock; |
| else |
| *f = 0; |
| } else { |
| // Read domino sampling frequency |
| unsigned char buffer[2]; |
| if (chipIndex == 0) |
| Read(T_STATUS, buffer, REG_FREQ1, 2); |
| else |
| Read(T_STATUS, buffer, REG_FREQ2, 2); |
| *f = (static_cast < unsigned int >(buffer[1]) << 8) +buffer[0]; |
| /* convert counts to frequency */ |
| if (*f != 0) |
| *f = 1024 * 200 * (32.768E6 * 4) / (*f) / 1E9; |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| double DRSBoard::VoltToFreq(double volt) |
| { |
| if (fDRSType == 3) { |
| if (volt <= 1.2001) |
| return (volt - 0.6) / 0.2; |
| else |
| return 0.73 / 0.28 + sqrt((0.73 / 0.28) * (0.73 / 0.28) - 2.2 / 0.14 + volt / 0.14); |
| } else |
| return (volt - 0.5) / 0.2; |
| } |
| /*------------------------------------------------------------------*/ |
| double DRSBoard::FreqToVolt(double freq) |
| { |
| if (fDRSType == 3) { |
| if (freq <= 3) |
| return 0.6 + 0.2 * freq; |
| else |
| return 2.2 - 0.73 * freq + 0.14 * freq * freq; |
| } else |
| return 0.55 + 0.25 * freq; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::ConfigureLMK(double sampFreq, bool freqChange, int calFreq, int calPhase) |
| { |
| unsigned int data[] = { 0x80000100, // RESET=1 |
| 0x0007FF00, // CLKOUT0: EN=1, DIV=FF (=510) MUX=Div&Delay |
| 0x00000101, // CLKOUT1: Disabled |
| 0x0082000B, // R11: DIV4=0 |
| 0x028780AD, // R13: VCO settings |
| 0x0830000E, // R14: PLL settings |
| 0xC000000F }; // R15: PLL settings |
| /* calculate dividing ratio */ |
| int divider, vco_divider, n_counter, r_counter; |
| unsigned int status; |
| double clk, vco; |
| if (fTransport == TR_USB2) { |
| /* 30 MHz clock */ |
| data[4] = 0x028780AD; // R13 according to CodeLoader 4 |
| clk = 30; |
| if (sampFreq < 1) { |
| r_counter = 1; |
| vco_divider = 8; |
| n_counter = 5; |
| } else { |
| r_counter = 1; |
| vco_divider = 5; |
| n_counter = 8; |
| } |
| } else { |
| if (fCtrlBits & BIT_REFCLK_SOURCE) { |
| /* 19.44 MHz clock */ |
| data[4] = 0x0284C0AD; // R13 according to CodeLoader 4 |
| clk = 19.44; // global clock through P2 |
| r_counter = 2; |
| vco_divider = 8; |
| n_counter = 16; |
| } else { |
| /* 33 MHz clock */ |
| data[4] = 0x028840AD; // R13 according to CodeLoader 4 |
| clk = 33; // FPGA clock |
| r_counter = 2; |
| vco_divider = 8; |
| n_counter = 9; |
| } |
| } |
| vco = clk/r_counter*n_counter*vco_divider; |
| divider = (int) ((vco / vco_divider / (sampFreq/2.048) / 2.0) + 0.5); |
| /* return exact frequency */ |
| fNominalFrequency = vco/vco_divider/(divider*2)*2.048; |
| /* return exact timing calibration frequency */ |
| fTCALFrequency = vco/vco_divider; |
| /* change registers accordingly */ |
| data[1] = 0x00070000 | (divider << 8); // R0 |
| data[5] = 0x0830000E | (r_counter << 8); // R14 |
| data[6] = 0xC000000F | (n_counter << 8) | (vco_divider << 26); // R15 |
| /* enable TCA output if requested */ |
| if (calFreq) { |
| if (calFreq == 1) |
| data[2] = 0x00050001 | ( 1<<8) ; // 148.5 MHz (33 MHz PLL) |
| // 150 MHz (30 MHz PLL) |
| // 155.52 MHz (19.44 MHz PLL) |
| else if (calFreq == 2) { |
| data[2] = 0x00070001 | ( 4<<8); // above values divided by 8 |
| fTCALFrequency /= 8; |
| } else if (calFreq == 3) { |
| data[2] = 0x00070001 | (255<<8); // above values divided by 510 |
| fTCALFrequency /= 510; |
| } |
| } |
| /* set delay to adjsut phase */ |
| if (calPhase > 0) |
| data[2] |= (( calPhase & 0x0F) << 4); |
| else if (calPhase < 0) |
| data[1] |= ((-calPhase & 0x0F) << 4); |
| if (freqChange) { |
| /* set all registers */ |
| for (int i=0 ; i<(int)(sizeof(data)/sizeof(unsigned int)) ; i++) { |
| Write(T_CTRL, REG_LMK_LSB, &data[i], 2); |
| Write(T_CTRL, REG_LMK_MSB, ((char *)&data[i])+2, 2); |
| // poll on serial_busy flag |
| for (int j=0 ; j<100 ; j++) { |
| Read(T_STATUS, &status, REG_STATUS, 4); |
| if ((status & BIT_SERIAL_BUSY) == 0) |
| break; |
| } |
| } |
| } else { |
| /* only enable/disable timing calibration frequency */ |
| Write(T_CTRL, REG_LMK_LSB, &data[1], 2); |
| Write(T_CTRL, REG_LMK_MSB, ((char *)&data[1])+2, 2); |
| /* poll on serial_busy flag */ |
| for (int j=0 ; j<100 ; j++) { |
| Read(T_STATUS, &status, REG_STATUS, 4); |
| if ((status & BIT_SERIAL_BUSY) == 0) |
| break; |
| } |
| Write(T_CTRL, REG_LMK_LSB, &data[2], 2); |
| Write(T_CTRL, REG_LMK_MSB, ((char *)&data[2])+2, 2); |
| /* poll on serial_busy flag */ |
| for (int j=0 ; j<100 ; j++) { |
| Read(T_STATUS, &status, REG_STATUS, 4); |
| if ((status & BIT_SERIAL_BUSY) == 0) |
| break; |
| } |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetFrequency(double demand, bool wait) |
| { |
| // Set domino sampling frequency |
| double freq, voltage, delta_voltage; |
| unsigned short ticks; |
| int i, index, timeout; |
| int dominoModeSave = fDominoMode; |
| int triggerEnableSave1 = fTriggerEnable1; |
| int triggerEnableSave2 = fTriggerEnable2; |
| if (fDRSType == 4) { |
| /* allowed range is 100 MHz to 6 GHz */ |
| if (demand > 6 || demand < 0.1) |
| return 0; |
| if (fBoardType == 6) { |
| for (i=1 ; i<100 ; i++) { |
| ConfigureLMK(demand, true, fTcalFreq, fTcalPhase); |
| Sleep(10); |
| if (IsLMKLocked()) |
| return 1; |
| printf("Re-start LMK in VME slot %2d %s\n", |
| (GetSlotNumber() >> 1)+2, ((GetSlotNumber() & 1) == 0) ? "upper" : "lower"); |
| } |
| return 0; |
| } |
| /* convert frequency in GHz into ticks counted by reference clock */ |
| if (demand == 0) |
| ticks = 0; // turn off frequency generation |
| else |
| ticks = static_cast < unsigned short >(1.024 / demand * fRefClock + 0.5); |
| ticks -= 2; // firmware counter need two additional clock cycles |
| Write(T_CTRL, REG_FREQ_SET, &ticks, 2); |
| ticks += 2; |
| /* convert rounded ticks back to frequency */ |
| if (demand > 0) |
| demand = 1.024 / ticks * fRefClock; |
| fNominalFrequency = demand; |
| /* wait for PLL lock if asked */ |
| if (wait) { |
| StartDomino(); |
| for (i=0 ; i<1000 ; i++) |
| if (GetStatusReg() & BIT_PLL_LOCKED0) |
| break; |
| SoftTrigger(); |
| if (i == 1000) { |
| printf("PLL did not lock for frequency %lf\n", demand); |
| return 0; |
| } |
| } |
| } else { // fDRSType == 4 |
| SetDominoMode(1); |
| EnableTrigger(0, 0); |
| EnableAcal(0, 0); |
| fNominalFrequency = demand; |
| /* turn automatic adjustment off */ |
| fCtrlBits &= ~BIT_FREQ_AUTO_ADJ; |
| /* disable external trigger */ |
| fCtrlBits &= ~BIT_ENABLE_TRIGGER1; |
| fCtrlBits &= ~BIT_ENABLE_TRIGGER2; |
| /* set start pulse length for future DRSBoard_domino_start() */ |
| if (fDRSType == 2) { |
| if (demand < 0.8) |
| fCtrlBits |= BIT_LONG_START_PULSE; |
| else |
| fCtrlBits &= ~BIT_LONG_START_PULSE; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| } |
| /* stop any running domino wave */ |
| Reinit(); |
| /* estimate DAC setting */ |
| voltage = FreqToVolt(demand); |
| SetDAC(fDAC_DSA, voltage); |
| SetDAC(fDAC_DSB, voltage); |
| /* wait until new DAC value has settled */ |
| Sleep(10); |
| /* restart domino wave */ |
| StartDomino(); |
| ticks = static_cast < unsigned short >(1024 * 200 * (32.768E6 * 4) / demand / 1E9); |
| /* iterate over both DRS chips */ |
| for (index = 0; index < 2; index++) { |
| /* starting voltage */ |
| voltage = FreqToVolt(demand); |
| for (i = 0; i < 100; i++) { |
| /* wait until measurement finished */ |
| for (timeout = 0; timeout < 1000; timeout++) |
| if (IsNewFreq(index)) |
| break; |
| freq = 0; |
| if (timeout == 1000) |
| break; |
| ReadFrequency(index, &freq); |
| delta_voltage = FreqToVolt(demand) - FreqToVolt(freq); |
| if (fDebug) { |
| if (fabs(freq - demand) < 0.001) |
| printf("CHIP-%d, iter%3d: %1.5lf(%05d) %7.5lf\n", index, i, voltage, |
| static_cast < int >(voltage / 2.5 * 65535 + 0.5), freq); |
| else |
| printf("CHIP-%d, iter%3d: %1.5lf(%05d) %7.5lf %+5d\n", index, i, voltage, |
| static_cast < int >(voltage / 2.5 * 65535 + 0.5), freq, |
| static_cast < int >(delta_voltage / 2.5 * 65535 + 0.5)); |
| } |
| if (fabs(freq - demand) < 0.001) |
| break; |
| voltage += delta_voltage; |
| if (voltage > 2.5) |
| voltage = 2.5; |
| if (voltage < 0) |
| voltage = 0; |
| if (freq == 0) |
| break; |
| if (index == 0) |
| SetDAC(fDAC_DSA, voltage); |
| else |
| SetDAC(fDAC_DSB, voltage); |
| Sleep(10); |
| } |
| if (i == 100 || freq == 0 || timeout == 1000) { |
| printf("Board %d --> Could not set frequency of CHIP-#%d to %1.3f GHz\n", GetBoardSerialNumber(), |
| index, demand); |
| return 0; |
| } |
| } |
| SetDominoMode(dominoModeSave); |
| EnableTrigger(triggerEnableSave1, triggerEnableSave2); |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::RegulateFrequency(double demand) |
| { |
| // Set frequency regulation |
| unsigned short target, target_hi, target_lo; |
| if (demand < 0.42 || demand > 5.2) |
| return 0; |
| fNominalFrequency = demand; |
| /* first iterate DAC value from host */ |
| if (!SetFrequency(demand, true)) |
| return 0; |
| /* convert frequency in GHz into counts for 200 cycles */ |
| target = static_cast < unsigned short >(1024 * 200 * (32.768E6 * 4) / demand / 1E9); |
| target_hi = target + 6; |
| target_lo = target - 6; |
| Write(T_CTRL, REG_FREQ_SET_HI, &target_hi, 2); |
| Write(T_CTRL, REG_FREQ_SET_LO, &target_lo, 2); |
| /* turn on regulation */ |
| fCtrlBits |= BIT_FREQ_AUTO_ADJ; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| /* optional monitoring code ... */ |
| #if 0 |
| do { |
| double freq; |
| unsigned short dac, cnt; |
| ReadFrequency(0, &freq); |
| if (fBoardType == 1) |
| Read(T_STATUS, &dac, REG_RDAC3, 2); |
| else if (fBoardType == 2 || fBoardType == 3) |
| Read(T_STATUS, &dac, REG_RDAC1, 2); |
| Read(T_STATUS, &cnt, REG_FREQ1, 2); |
| if (cnt < 65535) |
| printf("%5d %5d %5d %1.5lf\n", dac, target, cnt, freq); |
| Sleep(500); |
| } while (1); |
| #endif |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::RegisterTest() |
| { |
| // Register test |
| #define N_REG 8 |
| int i, n, n_err; |
| unsigned int buffer[N_REG], ret[N_REG]; |
| /* test single register */ |
| buffer[0] = 0x12345678; |
| Write(T_CTRL, 0, buffer, 4); |
| memset(ret, 0, sizeof(ret)); |
| i = Read(T_CTRL, ret, 0, 4); |
| while (i != 4) |
| printf("Read error single register!\n"); |
| printf("Reg.0: %08X - %08X\n", buffer[0], ret[0]); |
| n_err = 0; |
| for (n = 0; n < 100; n++) { |
| for (i = 0; i < N_REG; i++) |
| buffer[i] = (rand() << 16) | rand(); |
| Write(T_CTRL, 0, buffer, sizeof(buffer)); |
| memset(ret, 0, sizeof(ret)); |
| i = Read(T_CTRL, ret, 0, sizeof(ret)); |
| while (i != sizeof(ret)) { |
| printf("Read error!\n"); |
| return; |
| } |
| for (i = 0; i < N_REG; i++) { |
| if (n == 0) |
| printf("Reg.%d: %08X - %08X\n", i, buffer[i], ret[i]); |
| if (buffer[i] != ret[i]) { |
| n_err++; |
| } |
| } |
| } |
| printf("Register test: %d errors\n", n_err); |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::RAMTest(int flag) |
| { |
| #define MAX_N_BYTES 128*1024 // 128 kB |
| int i, j, n, bits, n_bytes, n_words, n_dwords; |
| unsigned int buffer[MAX_N_BYTES/4], ret[MAX_N_BYTES/4]; |
| time_t now; |
| if (fBoardType == 6 && fTransport == TR_VME) { |
| bits = 32; |
| n_bytes = 128*1024; // test full 128 kB |
| n_words = n_bytes/2; |
| n_dwords = n_words/2; |
| } else { |
| bits = 24; |
| n_words = 9*1024; |
| n_bytes = n_words * 2; |
| n_dwords = n_words/2; |
| } |
| if (flag & 1) { |
| /* integrety test */ |
| printf("Buffer size: %d (%1.1lfk)\n", n_words * 2, n_words * 2 / 1024.0); |
| if (flag & 1) { |
| for (i = 0; i < n_dwords; i++) { |
| if (bits == 24) |
| buffer[i] = (rand() | rand() << 16) & 0x00FFFFFF; // random 24-bit values |
| else |
| buffer[i] = (rand() | rand() << 16); // random 32-bit values |
| } |
| Reinit(); |
| Write(T_RAM, 0, buffer, n_bytes); |
| memset(ret, 0, n_bytes); |
| Read(T_RAM, ret, 0, n_bytes); |
| Reinit(); |
| for (i = n = 0; i < n_dwords; i++) { |
| if (buffer[i] != ret[i]) { |
| n++; |
| } |
| if (i < 10) |
| printf("written: %08X read: %08X\n", buffer[i], ret[i]); |
| } |
| printf("RAM test: %d errors\n", n); |
| } |
| } |
| /* speed test */ |
| if (flag & 2) { |
| /* read continously to determine speed */ |
| time(&now); |
| while (now == time(NULL)); |
| time(&now); |
| i = n = 0; |
| do { |
| memset(ret, 0, n_bytes); |
| for (j = 0; j < 10; j++) { |
| Read(T_RAM, ret, 0, n_bytes); |
| i += n_bytes; |
| } |
| if (flag & 1) { |
| for (j = 0; j < n_dwords; j++) |
| if (buffer[j] != ret[j]) |
| n++; |
| } |
| if (now != time(NULL)) { |
| if (flag & 1) |
| printf("%d read/sec, %1.2lf MB/sec, %d errors\n", static_cast < int >(i / n_bytes), |
| i / 1024.0 / 1024.0, n); |
| else |
| printf("%d read/sec, %1.2lf MB/sec\n", static_cast < int >(i / n_bytes), |
| i / 1024.0 / 1024.0); |
| time(&now); |
| i = 0; |
| } |
| if (drs_kbhit()) |
| break; |
| } while (1); |
| while (drs_kbhit()) |
| getch(); |
| } |
| return 0; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::ChipTest() |
| { |
| int i, j, t; |
| double freq, old_freq, min, max, mean, std; |
| float waveform[1024]; |
| Init(); |
| SetChannelConfig(0, 8, 8); |
| SetDominoMode(1); |
| SetReadoutMode(1); |
| SetDominoActive(1); |
| SetTranspMode(0); |
| EnableTrigger(0, 0); |
| EnableTcal(1, 0); |
| SelectClockSource(0); |
| EnableAcal(1, 0); |
| /* test 1 GHz */ |
| SetFrequency(1, true); |
| StartDomino(); |
| Sleep(100); |
| if (!(GetStatusReg() & BIT_PLL_LOCKED0)) { |
| puts("PLL did not lock at 1 GHz"); |
| return 0; |
| } |
| /* test up to 6 GHz */ |
| for (freq = 5 ; freq < 6 ; freq += 0.1) { |
| SetFrequency(freq, false); |
| Sleep(10); |
| if (!(GetStatusReg() & BIT_PLL_LOCKED0)) { |
| printf("Max. frequency is %1.1lf GHz\n", old_freq); |
| break; |
| } |
| ReadFrequency(0, &old_freq); |
| } |
| /* read and check at 0 calibration voltage */ |
| SetFrequency(5, true); |
| Sleep(10); |
| SoftTrigger(); |
| while (IsBusy()); |
| TransferWaves(0, 8); |
| for (i=0 ; i<8 ; i++) { |
| t = GetStopCell(0); |
| GetWave(0, i, waveform, false, t, 0, false); |
| for (j=0 ; j<1024; j++) |
| if (waveform[j] < -100 || waveform[j] > 100) { |
| if (j<5) { |
| /* skip this cells */ |
| } else { |
| printf("Cell error on channel %d, cell %d: %1.1lf mV instead 0 mV\n", i, j, waveform[j]); |
| return 0; |
| } |
| } |
| } |
| /* read and check at +0.5V calibration voltage */ |
| EnableAcal(1, 0.5); |
| StartDomino(); |
| SoftTrigger(); |
| while (IsBusy()); |
| TransferWaves(0, 8); |
| for (i=0 ; i<8 ; i++) { |
| t = GetStopCell(0); |
| GetWave(0, i, waveform, false, t, 0, false); |
| for (j=0 ; j<1024; j++) |
| if (waveform[j] < 350) { |
| if (j<5) { |
| /* skip this cell */ |
| } else { |
| printf("Cell error on channel %d, cell %d: %1.1lf mV instead 400 mV\n", i, j, waveform[j]); |
| return 0; |
| } |
| } |
| } |
| /* read and check at -0.5V calibration voltage */ |
| EnableAcal(1, -0.5); |
| StartDomino(); |
| Sleep(10); |
| SoftTrigger(); |
| while (IsBusy()); |
| TransferWaves(0, 8); |
| for (i=0 ; i<8 ; i++) { |
| t = GetStopCell(0); |
| GetWave(0, i, waveform, false, t, 0, false); |
| for (j=0 ; j<1024; j++) |
| if (waveform[j] > -350) { |
| if (j<5) { |
| /* skip this cell */ |
| } else { |
| printf("Cell error on channel %d, cell %d: %1.1lf mV instead -400mV\n", i, j, waveform[j]); |
| return 0; |
| } |
| } |
| } |
| /* check clock channel */ |
| GetWave(0, 8, waveform, false, 0, 0); |
| min = max = mean = std = 0; |
| for (j=0 ; j<1024 ; j++) { |
| if (waveform[j] > max) |
| max = waveform[j]; |
| if (waveform[j] < min) |
| min = waveform[j]; |
| mean += waveform[j]; |
| } |
| mean /= 1024.0; |
| for (j=0 ; j<1024 ; j++) |
| std += (waveform[j] - mean) * (waveform[j] - mean); |
| std = sqrt(std/1024); |
| if (max - min < 400) { |
| printf("Error on clock channel amplitude: %1.1lf mV\n", max-min); |
| return 0; |
| } |
| if (std < 100 || std > 300) { |
| printf("Error on clock channel Std: %1.1lf mV\n", std); |
| return 0; |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::SetVoltageOffset(double offset1, double offset2) |
| { |
| if (fDRSType == 3) { |
| SetDAC(fDAC_ROFS_1, 0.95 - offset1); |
| SetDAC(fDAC_ROFS_2, 0.95 - offset2); |
| } else if (fDRSType == 2) |
| SetDAC(fDAC_COFS, 0.9 - offset1); |
| // let DAC settle |
| Sleep(100); |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetInputRange(double center) |
| { |
| if (fBoardType == 5 || fBoardType == 6 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) { |
| // DRS4 USB Evaluation Boards + Mezzanine Board |
| // only allow -0.5...0.5 to 0...1.0 |
| if (center < 0 || center > 0.5) |
| return 0; |
| // remember range |
| fRange = center; |
| // correct for sampling cell charge injection |
| center *= 1.125; |
| // set readout offset |
| fROFS = 1.6 - center; |
| SetDAC(fDAC_ROFS_1, fROFS); |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetExternalClockFrequency(double frequencyMHz) |
| { |
| // Set the frequency of the external clock |
| fExternalClockFrequency = frequencyMHz; |
| return 0; |
| } |
| /*------------------------------------------------------------------*/ |
| double DRSBoard::GetExternalClockFrequency() |
| { |
| // Return the frequency of the external clock |
| return fExternalClockFrequency; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetMultiBuffer(int flag) |
| { |
| if (fHasMultiBuffer) { |
| // Enable/disable multi-buffering |
| fMultiBuffer = flag; |
| if (flag) |
| fCtrlBits |= BIT_MULTI_BUFFER; |
| else |
| fCtrlBits &= ~BIT_MULTI_BUFFER; |
| if (flag) { |
| if (fBoardType == 6) |
| fNMultiBuffer = 3; // 3 buffers for VME board |
| } else |
| fNMultiBuffer = 0; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::ResetMultiBuffer(void) |
| { |
| Reinit(); // set WP=0 |
| fReadPointer = 0; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::GetMultiBufferRP(void) |
| { |
| return fReadPointer; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetMultiBufferRP(unsigned short rp) |
| { |
| if (fHasMultiBuffer) { |
| fReadPointer = rp; |
| Write(T_CTRL, REG_READ_POINTER, &rp, 2); |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::GetMultiBufferWP(void) |
| { |
| unsigned short wp = 0; |
| if (fHasMultiBuffer) |
| Read(T_STATUS, &wp, REG_WRITE_POINTER, 2); |
| else |
| wp = 0; |
| return wp; |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::IncrementMultiBufferRP() |
| { |
| if (fHasMultiBuffer && fMultiBuffer) |
| SetMultiBufferRP((fReadPointer + 1) % fNMultiBuffer); |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::TransferWaves(int numberOfChannels) |
| { |
| return TransferWaves(fWaveforms, numberOfChannels); |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::TransferWaves(unsigned char *p, int numberOfChannels) |
| { |
| return TransferWaves(p, 0, numberOfChannels - 1); |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::TransferWaves(int firstChannel, int lastChannel) |
| { |
| int offset; |
| if (fTransport == TR_USB) |
| offset = firstChannel * sizeof(short int) * kNumberOfBins; |
| else |
| offset = 0; //in VME and USB2, always start from zero |
| return TransferWaves(fWaveforms + offset, firstChannel, lastChannel); |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::TransferWaves(unsigned char *p, int firstChannel, int lastChannel) |
| { |
| // Transfer all waveforms at once from VME or USB to location |
| int n, i, offset, n_requested, n_bins; |
| unsigned int dw; |
| unsigned short w; |
| unsigned char *ptr; |
| if (lastChannel >= fNumberOfChips * fNumberOfChannels) |
| lastChannel = fNumberOfChips * fNumberOfChannels - 1; |
| if (lastChannel < 0) { |
| printf("Error: Invalid channel index %d\n", lastChannel); |
| return 0; |
| } |
| if (firstChannel < 0 || firstChannel > fNumberOfChips * fNumberOfChannels) { |
| printf("Error: Invalid channel index %d\n", firstChannel); |
| return 0; |
| } |
| if (fTransport == TR_VME) { |
| /* in VME, always transfer all waveforms, since channels sit 'next' to each other */ |
| firstChannel = 0; |
| lastChannel = fNumberOfChips * fNumberOfChannels - 1; |
| if (fReadoutChannelConfig == 4) |
| lastChannel = fNumberOfChips * 5 - 1; // special mode to read only even channels + clock |
| } |
| else if (fTransport == TR_USB2) { |
| /* USB2 FPGA contains 9 (Eval) or 10 (Mezz) channels */ |
| firstChannel = 0; |
| if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) |
| lastChannel = 8; |
| else if (fBoardType == 6) |
| lastChannel = 9; |
| } |
| else if (fTransport == TR_USB) { |
| /* USB1 FPGA contains only 16 channels */ |
| if (lastChannel > 15) |
| lastChannel = 15; |
| } |
| n_bins = fDecimation ? kNumberOfBins/2 : kNumberOfBins; |
| n_requested = (lastChannel - firstChannel + 1) * sizeof(short int) * n_bins; |
| offset = firstChannel * sizeof(short int) * n_bins; |
| if (fBoardType == 6 && fFirmwareVersion >= 17147) |
| n_requested += 16; // add trailer four chips |
| if ((fBoardType == 7 || fBoardType == 8 || fBoardType == 9) && fFirmwareVersion >= 17147) |
| n_requested += 4; // add trailer one chip |
| if (fMultiBuffer) |
| offset += n_requested * fReadPointer; |
| n = Read(T_RAM, p, offset, n_requested); |
| if (fMultiBuffer) |
| IncrementMultiBufferRP(); |
| if (n != n_requested) { |
| printf("Error: only %d bytes read instead of %d\n", n, n_requested); |
| return n; |
| } |
| // read trigger cells |
| if (fDRSType == 4) { |
| if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) { |
| if ((fBoardType == 7 || fBoardType == 8 || fBoardType == 9) && fFirmwareVersion >= 17147) { |
| // new code reading trailer |
| ptr = p + n_requested - 4; |
| fStopCell[0] = *((unsigned short *)(ptr)); |
| fStopWSR[0] = *(ptr + 2); |
| } else { |
| // old code reading status register |
| Read(T_STATUS, fStopCell, REG_STOP_CELL0, 2); |
| Read(T_STATUS, &w, REG_STOP_WSR0, 2); |
| fStopWSR[0] = (w >> 8) & 0xFFFF; |
| } |
| } else { |
| if (fBoardType == 6) { |
| // new code reading trailer |
| ptr = p + n_requested - 16; |
| for (i=0 ; i<4 ; i++) { |
| fStopCell[i] = *((unsigned short *)(ptr + i*2)); |
| fStopWSR[i] = *(ptr + 8 + i); |
| } |
| fTriggerBus = *((unsigned short *)(ptr + 12)); |
| } else { |
| // old code reading registers |
| Read(T_STATUS, &dw, REG_STOP_CELL0, 4); |
| fStopCell[0] = (dw >> 16) & 0xFFFF; |
| fStopCell[1] = (dw >> 0) & 0xFFFF; |
| Read(T_STATUS, &dw, REG_STOP_CELL2, 4); |
| fStopCell[2] = (dw >> 16) & 0xFFFF; |
| fStopCell[3] = (dw >> 0) & 0xFFFF; |
| Read(T_STATUS, &dw, REG_STOP_WSR0, 4); |
| fStopWSR[0] = (dw >> 24) & 0xFF; |
| fStopWSR[1] = (dw >> 16) & 0xFF; |
| fStopWSR[2] = (dw >> 8) & 0xFF; |
| fStopWSR[3] = (dw >> 0) & 0xFF; |
| Read(T_STATUS, &fTriggerBus, REG_TRIGGER_BUS, 2); |
| } |
| } |
| } |
| return n; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::DecodeWave(unsigned int chipIndex, unsigned char channel, unsigned short *waveform) |
| { |
| return DecodeWave(fWaveforms, chipIndex, channel, waveform); |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::DecodeWave(unsigned char *waveforms, unsigned int chipIndex, unsigned char channel, |
| unsigned short *waveform) |
| { |
| // Get waveform |
| int i, offset=0, ind, n_bins; |
| /* check valid parameters */ |
| assert((int)channel < fNumberOfChannels); |
| assert((int)chipIndex < fNumberOfChips); |
| /* remap channel */ |
| if (fBoardType == 1) { |
| if (channel < 8) |
| channel = 7 - channel; |
| else |
| channel = 16 - channel; |
| } else if (fBoardType == 6) { |
| if (fReadoutChannelConfig == 7) { |
| if (channel < 8) |
| channel = 7-channel; |
| } else if (fReadoutChannelConfig == 4) { |
| if (channel == 8) |
| channel = 4; |
| else |
| channel = 3 - channel/2; |
| } else { |
| channel = channel / 2; |
| if (channel != 4) |
| channel = 3-channel; |
| } |
| } /* else |
| channel = channel; */ |
| // Read channel |
| if (fTransport == TR_USB) { |
| offset = kNumberOfBins * 2 * (chipIndex * 16 + channel); |
| for (i = 0; i < kNumberOfBins; i++) { |
| // 12-bit data |
| waveform[i] = ((waveforms[i * 2 + 1 + offset] & 0x0f) << 8) + waveforms[i * 2 + offset]; |
| } |
| } else if (fTransport == TR_USB2) { |
| if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) |
| // see dpram_map_eval1.xls |
| offset = kNumberOfBins * 2 * (chipIndex * 16 + channel); |
| else if (fBoardType == 6) { |
| // see dpram_map_mezz1.xls mode 0-3 |
| offset = (kNumberOfBins * 4) * (channel % 9) + 2 * (chipIndex/2); |
| } |
| for (i = 0; i < kNumberOfBins; i++) { |
| // 16-bit data |
| if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) |
| waveform[i] = ((waveforms[i * 2 + 1 + offset] & 0xff) << 8) + waveforms[i * 2 + offset]; |
| else if (fBoardType == 6) |
| waveform[i] = ((waveforms[i * 4 + 1 + offset] & 0xff) << 8) + waveforms[i * 4 + offset]; |
| } |
| } else if (fTransport == TR_VME) { |
| if (fBoardType == 6) { |
| n_bins = fDecimation ? kNumberOfBins/2 : kNumberOfBins; |
| if (fReadoutChannelConfig == 7) // see dpram_map_mezz1.xls mode 7 |
| offset = (n_bins * 4) * (channel % 9 + 9*(chipIndex % 2)) + 2 * (chipIndex/2); |
| else if (fReadoutChannelConfig == 4) // see dpram_map_mezz1.xls mode 4 |
| offset = (n_bins * 4) * (channel % 5 + 5*(chipIndex % 2)) + 2 * (chipIndex/2); |
| for (i = 0; i < n_bins; i++) |
| waveform[i] = ((waveforms[i * 4 + 1 + offset] & 0xff) << 8) + waveforms[i * 4 + offset]; |
| } else { |
| offset = (kNumberOfBins * 4) * channel; |
| for (i = 0; i < kNumberOfBins; i++) { |
| ind = i * 4 + offset; |
| if (chipIndex == 0) |
| // lower 12 bit |
| waveform[i] = ((waveforms[ind + 1] & 0x0f) << 8) | waveforms[ind]; |
| else |
| // upper 12 bit |
| waveform[i] = (waveforms[ind + 2] << 4) | (waveforms[ind + 1] >> 4); |
| } |
| } |
| } else { |
| printf("Error: invalid transport %d\n", fTransport); |
| return kInvalidTransport; |
| } |
| return kSuccess; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::GetWave(unsigned int chipIndex, unsigned char channel, float *waveform) |
| { |
| return GetWave(chipIndex, channel, waveform, true, fStopCell[chipIndex], -1, false, 0, true); |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::GetWave(unsigned int chipIndex, unsigned char channel, short *waveform, bool responseCalib, |
| int triggerCell, int wsr, bool adjustToClock, float threshold, bool offsetCalib) |
| { |
| return GetWave(fWaveforms, chipIndex, channel, waveform, responseCalib, triggerCell, wsr, adjustToClock, |
| threshold, offsetCalib); |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::GetWave(unsigned int chipIndex, unsigned char channel, float *waveform, bool responseCalib, |
| int triggerCell, int wsr, bool adjustToClock, float threshold, bool offsetCalib) |
| { |
| return GetWave(fWaveforms, chipIndex, channel, waveform, responseCalib, triggerCell, wsr, adjustToClock, threshold, |
| offsetCalib); |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::GetWave(unsigned char *waveforms, unsigned int chipIndex, unsigned char channel, |
| float *waveform, bool responseCalib, int triggerCell, int wsr, bool adjustToClock, |
| float threshold, bool offsetCalib) |
| { |
| int ret, i; |
| short waveS[2*kNumberOfBins]; |
| ret = |
| GetWave(waveforms, chipIndex, channel, waveS, responseCalib, triggerCell, wsr, adjustToClock, threshold, |
| offsetCalib); |
| if (responseCalib) |
| for (i = 0; i < fChannelDepth ; i++) |
| waveform[i] = static_cast < float >(static_cast <short> (waveS[i]) * GetPrecision()); |
| else { |
| for (i = 0; i < fChannelDepth ; i++) { |
| if (fBoardType == 4 || fBoardType == 5 || fBoardType == 6 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) { |
| waveform[i] = static_cast < float >(waveS[i] * GetPrecision()); |
| } else |
| waveform[i] = static_cast < float >(waveS[i]); |
| } |
| } |
| return ret; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::GetWave(unsigned char *waveforms, unsigned int chipIndex, unsigned char channel, |
| short *waveform, bool responseCalib, int triggerCell, int wsr, bool adjustToClock, |
| float threshold, bool offsetCalib) |
| { |
| unsigned short adcWaveform[kNumberOfBins]; |
| int i, ret; |
| if (fChannelCascading == 1 || channel == 8) { |
| /* single channel configuration */ |
| ret = DecodeWave(waveforms, chipIndex, channel, adcWaveform); |
| if (ret != kSuccess) |
| return ret; |
| ret = CalibrateWaveform(chipIndex, channel, adcWaveform, waveform, responseCalib, |
| triggerCell, adjustToClock, threshold, offsetCalib); |
| return ret; |
| } else if (fChannelCascading == 2) { |
| /* double channel configuration */ |
| short wf1[kNumberOfBins]; |
| short wf2[kNumberOfBins]; |
| // first half |
| ret = DecodeWave(waveforms, chipIndex, 2*channel, adcWaveform); |
| if (ret != kSuccess) |
| return ret; |
| ret = CalibrateWaveform(chipIndex, 2*channel, adcWaveform, wf1, responseCalib, |
| triggerCell, adjustToClock, threshold, offsetCalib); |
| // second half |
| ret = DecodeWave(waveforms, chipIndex, 2*channel+1, adcWaveform); |
| if (ret != kSuccess) |
| return ret; |
| ret = CalibrateWaveform(chipIndex, 2*channel+1, adcWaveform, wf2, responseCalib, |
| triggerCell, adjustToClock, threshold, offsetCalib); |
| // combine two halfs correctly, see 2048_mode.ppt |
| if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) { |
| if ((wsr == 0 && triggerCell < 767) || |
| (wsr == 1 && triggerCell >= 767)) { |
| for (i=0 ; i<kNumberOfBins-triggerCell ; i++) |
| waveform[i] = wf1[i]; |
| for (; i<kNumberOfBins; i++) |
| waveform[i] = wf2[i]; |
| for (i=0 ; i<kNumberOfBins-triggerCell ; i++) |
| waveform[i+kNumberOfBins] = wf2[i]; |
| for (; i<kNumberOfBins; i++) |
| waveform[i+kNumberOfBins] = wf1[i]; |
| } else { |
| for (i=0 ; i<kNumberOfBins-triggerCell ; i++) |
| waveform[i] = wf2[i]; |
| for (; i<kNumberOfBins; i++) |
| waveform[i] = wf1[i]; |
| for (i=0 ; i<kNumberOfBins-triggerCell ; i++) |
| waveform[i+kNumberOfBins] = wf1[i]; |
| for (; i<kNumberOfBins; i++) |
| waveform[i+kNumberOfBins] = wf2[i]; |
| } |
| } else { |
| if (wsr == 1) { |
| if (fDecimation) { |
| for (i=0 ; i<kNumberOfBins/2-triggerCell/2 ; i++) |
| waveform[i] = wf1[i]; |
| for (; i<kNumberOfBins/2; i++) |
| waveform[i] = wf2[i]; |
| for (i=0 ; i<kNumberOfBins/2-triggerCell/2 ; i++) |
| waveform[i+kNumberOfBins/2] = wf2[i]; |
| for (; i<kNumberOfBins/2; i++) |
| waveform[i+kNumberOfBins/2] = wf1[i]; |
| } else { |
| for (i=0 ; i<kNumberOfBins-triggerCell ; i++) |
| waveform[i] = wf1[i]; |
| for (; i<kNumberOfBins; i++) |
| waveform[i] = wf2[i]; |
| for (i=0 ; i<kNumberOfBins-triggerCell ; i++) |
| waveform[i+kNumberOfBins] = wf2[i]; |
| for (; i<kNumberOfBins; i++) |
| waveform[i+kNumberOfBins] = wf1[i]; |
| } |
| } else { |
| if (fDecimation) { |
| for (i=0 ; i<kNumberOfBins/2-triggerCell/2 ; i++) |
| waveform[i] = wf2[i]; |
| for (; i<kNumberOfBins/2; i++) |
| waveform[i] = wf1[i]; |
| for (i=0 ; i<kNumberOfBins/2-triggerCell/2 ; i++) |
| waveform[i+kNumberOfBins/2] = wf1[i]; |
| for (; i<kNumberOfBins/2; i++) |
| waveform[i+kNumberOfBins/2] = wf2[i]; |
| } else { |
| for (i=0 ; i<kNumberOfBins-triggerCell ; i++) |
| waveform[i] = wf2[i]; |
| for (; i<kNumberOfBins; i++) |
| waveform[i] = wf1[i]; |
| for (i=0 ; i<kNumberOfBins-triggerCell ; i++) |
| waveform[i+kNumberOfBins] = wf1[i]; |
| for (; i<kNumberOfBins; i++) |
| waveform[i+kNumberOfBins] = wf2[i]; |
| } |
| } |
| } |
| return ret; |
| } else |
| assert(!"Not implemented"); |
| return 0; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::GetRawWave(unsigned int chipIndex, unsigned char channel, unsigned short *waveform, |
| bool adjustToClock) |
| { |
| return GetRawWave(fWaveforms, chipIndex, channel, waveform, adjustToClock); |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::GetRawWave(unsigned char *waveforms, unsigned int chipIndex, unsigned char channel, |
| unsigned short *waveform, bool adjustToClock) |
| { |
| int i, status, tc; |
| unsigned short wf[kNumberOfBins]; |
| status = DecodeWave(waveforms, chipIndex, channel, wf); |
| if (adjustToClock) { |
| tc = GetTriggerCell(chipIndex); |
| for (i = 0 ; i < kNumberOfBins; i++) |
| waveform[(i + tc) % kNumberOfBins] = wf[i]; |
| } else { |
| for (i = 0 ; i < kNumberOfBins; i++) |
| waveform[i] = wf[i]; |
| } |
| return status; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::CalibrateWaveform(unsigned int chipIndex, unsigned char channel, unsigned short *adcWaveform, |
| short *waveform, bool responseCalib, |
| int triggerCell, bool adjustToClock, float threshold, bool offsetCalib) |
| { |
| int j, n_bins, skip; |
| double value; |
| short left, right; |
| // calibrate waveform |
| if (responseCalib && fVoltageCalibrationValid) { |
| if (GetDRSType() == 4) { |
| // if Mezz though USB2 -> select correct calibration channel |
| if (fBoardType == 6 && (fReadoutChannelConfig == 0 || fReadoutChannelConfig == 2) && |
| channel != 8) |
| channel++; |
| // Channel readout mode #4 -> select correct calibration channel |
| if (fBoardType == 6 && fReadoutChannelConfig == 4 && channel % 2 == 0 && channel != 8) |
| channel++; |
| n_bins = fDecimation ? kNumberOfBins/2 : kNumberOfBins; |
| skip = fDecimation ? 2 : 1; |
| for (j = 0; j < n_bins; j++) { |
| value = adcWaveform[j] - fCellOffset[channel+chipIndex*9][(j*skip + triggerCell) % kNumberOfBins]; |
| value = value / fCellGain[channel+chipIndex*9][(j*skip + triggerCell) % kNumberOfBins]; |
| if (offsetCalib && channel != 8) |
| value = value - fCellOffset2[channel+chipIndex*9][j*skip] + 32768; |
| /* convert to units of 0.1 mV */ |
| value = value / 65536.0 * 1000 * 10; |
| /* apply clipping */ |
| if (channel != 8) { |
| if (adcWaveform[j] >= 0xFFF0 || value > (fRange * 1000 + 500) * 10) |
| value = (fRange * 1000 + 500) * 10; |
| if (adcWaveform[j] < 0x0010 || value < (fRange * 1000 - 500) * 10) |
| value = (fRange * 1000 - 500) * 10; |
| } |
| if (adjustToClock) |
| waveform[(j + triggerCell) % kNumberOfBins] = (short) (value + 0.5); |
| else |
| waveform[j] = (short) (value + 0.5); |
| } |
| // check for stuck pixels and replace by average of neighbors |
| for (j = 0 ; j < n_bins; j++) { |
| if (adjustToClock) { |
| if (fCellOffset[channel+chipIndex*9][j*skip] == 0) { |
| left = waveform[(j-1+kNumberOfBins) % kNumberOfBins]; |
| right = waveform[(j+1) % kNumberOfBins]; |
| waveform[j] = (short) ((left+right)/2); |
| } |
| } else { |
| if (fCellOffset[channel+chipIndex*9][(j*skip + triggerCell) % kNumberOfBins] == 0) { |
| left = waveform[(j-1+kNumberOfBins) % kNumberOfBins]; |
| right = waveform[(j+1) % kNumberOfBins]; |
| waveform[j] = (short) ((left+right)/2); |
| } |
| } |
| } |
| } else { |
| if (!fResponseCalibration-> |
| Calibrate(chipIndex, channel % 10, adcWaveform, waveform, triggerCell, threshold, offsetCalib)) |
| return kZeroSuppression; // return immediately if below threshold |
| } |
| } else { |
| if (GetDRSType() == 4) { |
| // if Mezz though USB2 -> select correct calibration channel |
| if (fBoardType == 6 && (fReadoutChannelConfig == 0 || fReadoutChannelConfig == 2) && |
| channel != 8) |
| channel++; |
| for (j = 0 ; j < kNumberOfBins; j++) { |
| value = adcWaveform[j]; |
| /* convert to units of 0.1 mV */ |
| value = (value - 32768) / 65536.0 * 1000 * 10; |
| /* correct for range */ |
| value += fRange * 1000 * 10; |
| if (adjustToClock) |
| waveform[(j + triggerCell) % kNumberOfBins] = (short) (value + 0.5); |
| else |
| waveform[j] = (short) (value + 0.5); |
| } |
| } else { |
| for (j = 0; j < kNumberOfBins; j++) { |
| if (adjustToClock) { |
| // rotate waveform such that waveform[0] corresponds to bin #0 on the chip |
| waveform[j] = adcWaveform[(kNumberOfBins-triggerCell+j) % kNumberOfBins]; |
| } else { |
| waveform[j] = adcWaveform[j]; |
| } |
| } |
| } |
| } |
| // fix bad cells for single turn mode |
| if (GetDRSType() == 2) { |
| if (fDominoMode == 0 && triggerCell == -1) { |
| waveform[0] = 2 * waveform[1] - waveform[2]; |
| short m1 = (waveform[kNumberOfBins - 5] + waveform[kNumberOfBins - 6]) / 2; |
| short m2 = (waveform[kNumberOfBins - 6] + waveform[kNumberOfBins - 7]) / 2; |
| waveform[kNumberOfBins - 4] = m1 - 1 * (m2 - m1); |
| waveform[kNumberOfBins - 3] = m1 - 2 * (m2 - m1); |
| waveform[kNumberOfBins - 2] = m1 - 3 * (m2 - m1); |
| waveform[kNumberOfBins - 1] = m1 - 4 * (m2 - m1); |
| } |
| } |
| return kSuccess; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::GetStretchedTime(float *time, float *measurement, int numberOfMeasurements, float period) |
| { |
| int j; |
| if (*time >= measurement[numberOfMeasurements - 1]) { |
| *time -= measurement[numberOfMeasurements - 1]; |
| return 1; |
| } |
| if (*time < measurement[0]) { |
| *time = *time - measurement[0] - (numberOfMeasurements - 1) * period / 2; |
| return 1; |
| } |
| for (j = 0; j < numberOfMeasurements - 1; j++) { |
| if (*time > measurement[j] && *time <= measurement[j + 1]) { |
| *time = |
| (period / 2) / (measurement[j + 1] - measurement[j]) * (*time - measurement[j + 1]) - |
| (numberOfMeasurements - 2 - j) * period / 2; |
| return 1; |
| } |
| } |
| return 0; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::GetTriggerCell(unsigned int chipIndex) |
| { |
| if (fDRSType == 4) |
| return GetStopCell(chipIndex); |
| return GetTriggerCell(fWaveforms, chipIndex); |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::GetTriggerCell(unsigned char *waveforms, unsigned int chipIndex) |
| { |
| int j, triggerCell; |
| bool calib; |
| unsigned short baseLevel = 1000; |
| unsigned short triggerChannel[1024]; |
| if (fDRSType == 4) |
| return GetStopCell(chipIndex); |
| GetRawWave(waveforms, chipIndex, 8, triggerChannel); |
| calib = fResponseCalibration->SubtractADCOffset(chipIndex, 8, triggerChannel, triggerChannel, baseLevel); |
| triggerCell = -1; |
| for (j = 0; j < kNumberOfBins; j++) { |
| if (calib) { |
| if (triggerChannel[j] <= baseLevel + 200 |
| && triggerChannel[(j + 1) % kNumberOfBins] > baseLevel + 200) { |
| triggerCell = j; |
| break; |
| } |
| } else { |
| if (fDRSType == 3) { |
| if (triggerChannel[j] <= 2000 && triggerChannel[(j + 1) % kNumberOfBins] > 2000) { |
| triggerCell = j; |
| break; |
| } |
| } else { |
| if (triggerChannel[j] >= 2000 && triggerChannel[(j + 1) % kNumberOfBins] < 2000) { |
| triggerCell = j; |
| break; |
| } |
| } |
| } |
| } |
| if (triggerCell == -1) { |
| return kInvalidTriggerSignal; |
| } |
| fStopCell[0] = triggerCell; |
| return triggerCell; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::GetStopCell(unsigned int chipIndex) |
| { |
| return fStopCell[chipIndex]; |
| } |
| /*------------------------------------------------------------------*/ |
| unsigned char DRSBoard::GetStopWSR(unsigned int chipIndex) |
| { |
| return fStopWSR[chipIndex]; |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::TestDAC(int channel) |
| { |
| // Test DAC |
| int status; |
| do { |
| status = SetDAC(channel, 0); |
| Sleep(1000); |
| status = SetDAC(channel, 0.5); |
| Sleep(1000); |
| status = SetDAC(channel, 1); |
| Sleep(1000); |
| status = SetDAC(channel, 1.5); |
| Sleep(1000); |
| status = SetDAC(channel, 2); |
| Sleep(1000); |
| status = SetDAC(channel, 2.5); |
| Sleep(1000); |
| } while (status); |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::MeasureSpeed() |
| { |
| // Measure domino sampling speed |
| FILE *f; |
| double vdr, vds, freq; |
| f = fopen("speed.txt", "wt"); |
| fprintf(f, "\t"); |
| printf("\t"); |
| for (vdr = 0.5; vdr <= 2.501; vdr += 0.05) { |
| fprintf(f, "%1.2lf\t", vdr); |
| printf("%1.2lf\t", vdr); |
| } |
| fprintf(f, "\n"); |
| printf("\n"); |
| for (vds = 0.5; vds <= 2.501; vds += 0.05) { |
| fprintf(f, "%1.2lf\t", vds); |
| printf("%1.2lf\t", vds); |
| SetDAC(fDAC_DSA, vds); |
| StartDomino(); |
| Sleep(1000); |
| ReadFrequency(0, &freq); |
| fprintf(f, "%1.3lf\t", freq); |
| printf("%1.3lf\t", freq); |
| fprintf(f, "\n"); |
| printf("\n"); |
| fflush(f); |
| } |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::InteractSpeed() |
| { |
| int status, i; |
| double freq, vds; |
| do { |
| printf("DS: "); |
| scanf("%lf", &vds); |
| if (vds == 0) |
| break; |
| SetDAC(fDAC_DSA, vds); |
| SetDAC(fDAC_DSB, vds); |
| StartDomino(); |
| for (i = 0; i < 4; i++) { |
| Sleep(1000); |
| status = ReadFrequency(0, &freq); |
| if (!status) |
| break; |
| printf("%1.6lf GHz\n", freq); |
| } |
| /* turn BOARD_LED off */ |
| SetLED(0); |
| } while (1); |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::MonitorFrequency() |
| { |
| // Monitor domino sampling frequency |
| int status; |
| unsigned int data; |
| double freq, dac; |
| FILE *f; |
| time_t now; |
| char str[256]; |
| f = fopen("DRSBoard.log", "w"); |
| do { |
| Sleep(1000); |
| status = ReadFrequency(0, &freq); |
| if (!status) |
| break; |
| data = 0; |
| if (fBoardType == 1) |
| Read(T_STATUS, &data, REG_RDAC3, 2); |
| else if (fBoardType == 2 || fBoardType == 3) |
| Read(T_STATUS, &data, REG_RDAC1, 2); |
| dac = data / 65536.0 * 2.5; |
| printf("%1.6lf GHz, %1.4lf V\n", freq, dac); |
| time(&now); |
| strcpy(str, ctime(&now) + 11); |
| str[8] = 0; |
| fprintf(f, "%s %1.6lf GHz, %1.4lf V\n", str, freq, dac); |
| fflush(f); |
| } while (!drs_kbhit()); |
| fclose(f); |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::TestShift(int n) |
| { |
| // Test shift register |
| unsigned char buffer[3]; |
| memset(buffer, 0, sizeof(buffer)); |
| #if 0 |
| buffer[0] = CMD_TESTSHIFT; |
| buffer[1] = n; |
| status = msend_usb(buffer, 2); |
| if (status != 2) |
| return status; |
| status = mrecv_usb(buffer, sizeof(buffer)); |
| if (status != 1) |
| return status; |
| #endif |
| if (buffer[0] == 1) |
| printf("Shift register %c works correctly\n", 'A' + n); |
| else if (buffer[0] == 2) |
| printf("SROUT%c does hot go high after reset\n", 'A' + n); |
| else if (buffer[0] == 3) |
| printf("SROUT%c does hot go low after 1024 clocks\n", 'A' + n); |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| unsigned int DRSBoard::GetCtrlReg() |
| { |
| unsigned int status; |
| Read(T_CTRL, &status, REG_CTRL, 4); |
| return status; |
| } |
| /*------------------------------------------------------------------*/ |
| unsigned short DRSBoard::GetConfigReg() |
| { |
| unsigned short status; |
| Read(T_CTRL, &status, REG_CONFIG, 2); |
| return status; |
| } |
| /*------------------------------------------------------------------*/ |
| unsigned int DRSBoard::GetStatusReg() |
| { |
| unsigned int status; |
| Read(T_STATUS, &status, REG_STATUS, 4); |
| return status; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::EnableTcal(int freq, int level, int phase) |
| { |
| fTcalFreq = freq; |
| fTcalLevel = level; |
| fTcalPhase = phase; |
| if (fBoardType == 6) { |
| ConfigureLMK(fNominalFrequency, false, freq, phase); |
| } else { |
| if (fBoardType == 9) { |
| // Enable clock a switch channel multiplexers |
| if (freq) { |
| fCtrlBits |= (BIT_TCAL_EN | BIT_ACAL_EN); |
| } else |
| fCtrlBits &= ~(BIT_TCAL_EN | BIT_ACAL_EN); |
| } else { |
| // Enable clock channel |
| if (freq) |
| fCtrlBits |= BIT_TCAL_EN; |
| else |
| fCtrlBits &= ~(BIT_TCAL_EN | BIT_TCAL_SOURCE); |
| // Set output level, needed for gain calibration |
| if (fDRSType == 4) { |
| if (level) |
| fCtrlBits |= BIT_NEG_TRIGGER; |
| else |
| fCtrlBits &= ~BIT_NEG_TRIGGER; |
| } |
| } |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SelectClockSource(int source) |
| { |
| fTcalSource = source; |
| // Select clock source: |
| // EVAL1: synchronous (0) or asynchronous (1) (2nd quartz) |
| if (fBoardType <= 8) { |
| if (source) |
| fCtrlBits |= BIT_TCAL_SOURCE; |
| else |
| fCtrlBits &= ~BIT_TCAL_SOURCE; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetRefclk(int source) |
| { |
| // Select reference clock source to internal FPGA (0) or external P2 (1) |
| if (fBoardType == 6) { |
| if (source) |
| fCtrlBits |= BIT_REFCLK_SOURCE; |
| else |
| fCtrlBits &= ~BIT_REFCLK_SOURCE; |
| } else if (fBoardType == 8 || fBoardType == 9) { |
| if (source) |
| fCtrlBits |= BIT_REFCLK_EXT; |
| else |
| fCtrlBits &= ~BIT_REFCLK_EXT; |
| } |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| fRefclk = source; |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::EnableAcal(int mode, double voltage) |
| { |
| double t1, t2; |
| fAcalMode = mode; |
| fAcalVolt = voltage; |
| if (mode == 0) { |
| /* turn calibration off */ |
| SetCalibTiming(0, 0); |
| if (fBoardType == 5 || fBoardType == 6) { |
| /* turn voltages off (50 Ohm analog switch!) */ |
| SetDAC(fDAC_CALP, 0); |
| SetDAC(fDAC_CALN, 0); |
| } |
| if (fBoardType == 7 || fBoardType == 8 || fBoardType == 9) |
| SetCalibVoltage(0); |
| fCtrlBits &= ~BIT_ACAL_EN; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| } else if (mode == 1) { |
| /* static calibration */ |
| SetCalibVoltage(voltage); |
| SetCalibTiming(0, 0); |
| fCtrlBits |= BIT_ACAL_EN; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| } else if (mode == 2) { |
| /* first part calibration: |
| stop domino wave after 1.2 revolutions |
| turn on calibration voltage after 0.1 revolutions */ |
| /* ensure circulating domino wave */ |
| SetDominoMode(1); |
| /* set calibration voltage but do not turn it on now */ |
| SetCalibVoltage(voltage); |
| fCtrlBits &= ~BIT_ACAL_EN; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| /* calculate duration of DENABLE signal as 1.2 revolutions */ |
| t1 = 1 / fNominalFrequency * 1024 * 1.2; // ns |
| t1 = static_cast < int >((t1 - 30) / 30 + 1); // 30 ns offset, 30 ns units, rounded up |
| t2 = 1 / fNominalFrequency * 1024 * 0.1; // ns |
| t2 = static_cast < int >((t2 - 30) / 30 + 1); // 30 ns offset, 30 ns units, rounded up |
| SetCalibTiming(static_cast < int >(t1), static_cast < int >(t2)); |
| } else if (mode == 3) { |
| /* second part calibration: |
| stop domino wave after 1.05 revolutions */ |
| /* ensure circulating domino wave */ |
| SetDominoMode(1); |
| /* turn on and let settle calibration voltage */ |
| SetCalibVoltage(voltage); |
| fCtrlBits |= BIT_ACAL_EN; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| /* calculate duration of DENABLE signal as 1.1 revolutions */ |
| t1 = 1 / fNominalFrequency * 1024 * 1.05; // ns |
| t1 = static_cast < int >((t1 - 30) / 30 + 1); // 30 ns offset, 30 ns units, rounded up |
| SetCalibTiming(static_cast < int >(t1), 0); |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetCalibTiming(int t_enable, int t_cal) |
| { |
| unsigned short d; |
| if (fDRSType == 2) { |
| d = t_cal | (t_enable << 8); |
| Write(T_CTRL, REG_CALIB_TIMING, &d, 2); |
| } |
| if (fDRSType == 3) { |
| d = t_cal; |
| Write(T_CTRL, REG_CALIB_TIMING, &d, 2); |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetCalibVoltage(double value) |
| { |
| // Set Calibration Voltage |
| if (fBoardType == 5 || fBoardType == 6 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) { |
| if (fBoardType == 5) |
| value = value * (1+fNominalFrequency/65); // rough correction factor for input current |
| if (fBoardType == 7 || fBoardType == 8 || fBoardType == 9) |
| value = value * (1+fNominalFrequency/47); // rough correction factor for input current |
| SetDAC(fDAC_CALP, fCommonMode + value / 2); |
| SetDAC(fDAC_CALN, fCommonMode - value / 2); |
| } else |
| SetDAC(fDAC_ACALIB, value); |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::StartClearCycle() |
| { |
| /* clear cycle is necessary for DRS4 to reduce noise */ |
| fbkAcalVolt = fAcalVolt; |
| fbkAcalMode = fAcalMode; |
| fbkTcalFreq = fTcalFreq; |
| fbkTcalLevel = fTcalLevel; |
| /* switch all inputs to zero */ |
| EnableAcal(1, 0); |
| /* start, stop and readout of zero */ |
| StartDomino(); |
| SoftTrigger(); |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::FinishClearCycle() |
| { |
| while (IsBusy()); |
| /* restore old values */ |
| EnableAcal(fbkAcalMode, fbkAcalVolt); |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| double DRSBoard::GetTemperature() |
| { |
| // Read Out Temperature Sensor |
| unsigned char buffer[2]; |
| unsigned short d; |
| double temperature; |
| Read(T_STATUS, buffer, REG_TEMPERATURE, 2); |
| d = (static_cast < unsigned int >(buffer[1]) << 8) +buffer[0]; |
| temperature = ((d >> 3) & 0x0FFF) * 0.0625; |
| return temperature; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::Is2048ModeCapable() |
| { |
| unsigned int status; |
| if (fFirmwareVersion < 21305) |
| return 0; |
| // Read pin J44 and return 1 if 2048 mode has been soldered |
| Read(T_STATUS, &status, REG_STATUS, 4); |
| if ((status & BIT_2048_MODE)) |
| return 0; |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::GetTriggerBus() |
| { |
| unsigned size, d; |
| if (fBoardType == 6 && fTransport == TR_VME) { |
| if (fReadoutChannelConfig == 4) |
| size = (20 * sizeof(short int) * (fDecimation ? kNumberOfBins/2 : kNumberOfBins) + 16); |
| else |
| size = (36 * sizeof(short int) * (fDecimation ? kNumberOfBins/2 : kNumberOfBins) + 16); |
| Read(T_RAM, &d, size * fReadPointer + size - 16 + 12, 4); |
| fTriggerBus = (unsigned short)d; |
| } else { |
| Read(T_STATUS, &fTriggerBus, REG_TRIGGER_BUS, 2); |
| } |
| return static_cast < int >(fTriggerBus); |
| } |
| /*------------------------------------------------------------------*/ |
| unsigned int DRSBoard::GetScaler(int channel) |
| { |
| int reg = 0; |
| unsigned d; |
| if (fBoardType < 9 || fFirmwareVersion < 21000 || fTransport != TR_USB2) |
| return 0; |
| switch (channel ) { |
| case 0: reg = REG_SCALER0; break; |
| case 1: reg = REG_SCALER1; break; |
| case 2: reg = REG_SCALER2; break; |
| case 3: reg = REG_SCALER3; break; |
| case 4: reg = REG_SCALER4; break; |
| case 5: reg = REG_SCALER5; break; |
| } |
| Read(T_STATUS, &d, reg, 4); |
| return static_cast < unsigned int >(d * 10); // measurement clock is 10 Hz |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::SetBoardSerialNumber(unsigned short serialNumber) |
| { |
| unsigned char buf[32768]; |
| unsigned short dac; |
| if (fDRSType < 4) { |
| // read current DAC register |
| Read(T_CTRL, &dac, REG_DAC0, 2); |
| // put serial in DAC register |
| Write(T_CTRL, REG_DAC0, &serialNumber, 2); |
| // execute flash |
| fCtrlBits |= BIT_EEPROM_WRITE_TRIG; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| fCtrlBits &= ~BIT_EEPROM_WRITE_TRIG; |
| // wait 6ms per word |
| Sleep(20); |
| // write back old DAC registers |
| Write(T_CTRL, REG_DAC0, &dac, 2); |
| // read back serial number |
| ReadSerialNumber(); |
| } else if (fDRSType == 4) { |
| /* merge serial number into eeprom page #0 */ |
| ReadEEPROM(0, buf, sizeof(buf)); |
| buf[0] = serialNumber & 0xFF; |
| buf[1] = serialNumber >> 8; |
| WriteEEPROM(0, buf, sizeof(buf)); |
| /* erase DPRAM */ |
| memset(buf, 0, sizeof(buf)); |
| Write(T_RAM, 0, buf, sizeof(buf)); |
| /* read back EEPROM */ |
| ReadEEPROM(0, buf, sizeof(buf)); |
| /* check if correctly set */ |
| if (((buf[1] << 8) | buf[0]) != serialNumber) |
| return 0; |
| fBoardSerialNumber = serialNumber; |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::ReadEEPROM(unsigned short page, void *buffer, int size) |
| { |
| int i; |
| unsigned long status; |
| // write eeprom page number |
| if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) |
| Write(T_CTRL, REG_EEPROM_PAGE_EVAL, &page, 2); |
| else if (fBoardType == 6) |
| Write(T_CTRL, REG_EEPROM_PAGE_MEZZ, &page, 2); |
| else |
| return -1; |
| // execute eeprom read |
| fCtrlBits |= BIT_EEPROM_READ_TRIG; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| fCtrlBits &= ~BIT_EEPROM_READ_TRIG; |
| // poll on serial_busy flag |
| for (i=0 ; i<100 ; i++) { |
| Read(T_STATUS, &status, REG_STATUS, 4); |
| if ((status & BIT_SERIAL_BUSY) == 0) |
| break; |
| Sleep(10); |
| } |
| return Read(T_RAM, buffer, 0, size); |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::WriteEEPROM(unsigned short page, void *buffer, int size) |
| { |
| int i; |
| unsigned long status; |
| unsigned char buf[32768]; |
| // read previous page |
| ReadEEPROM(page, buf, sizeof(buf)); |
| // combine with new page |
| memcpy(buf, buffer, size); |
| // write eeprom page number |
| if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) |
| Write(T_CTRL, REG_EEPROM_PAGE_EVAL, &page, 2); |
| else if (fBoardType == 6) |
| Write(T_CTRL, REG_EEPROM_PAGE_MEZZ, &page, 2); |
| else |
| return -1; |
| // write eeprom page to RAM |
| Write(T_RAM, 0, buf, size); |
| // execute eeprom write |
| fCtrlBits |= BIT_EEPROM_WRITE_TRIG; |
| Write(T_CTRL, REG_CTRL, &fCtrlBits, 4); |
| fCtrlBits &= ~BIT_EEPROM_WRITE_TRIG; |
| // poll on serail_busy flag |
| for (i=0 ; i<500 ; i++) { |
| Read(T_STATUS, &status, REG_STATUS, 4); |
| if ((status & BIT_SERIAL_BUSY) == 0) |
| break; |
| Sleep(10); |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| bool DRSBoard::IsTimingCalibrationValid() |
| { |
| return fabs(fNominalFrequency - fTimingCalibratedFrequency) < 0.001; |
| } |
| double DRSBoard::GetTrueFrequency() |
| { |
| int i; |
| double f; |
| if (IsTimingCalibrationValid()) { |
| /* calculate true frequency */ |
| for (i=0,f=0 ; i<1024 ; i++) |
| f += fCellDT[0][0][i]; |
| f = 1024.0 / f; |
| } else |
| f = fNominalFrequency; |
| return f; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::GetTime(unsigned int chipIndex, int channelIndex, int tc, float *time, bool tcalibrated, bool rotated) |
| { |
| int i, scale, iend; |
| double gt0, gt; |
| /* for DRS2, please use function below */ |
| if (fDRSType < 4) |
| return GetTime(chipIndex, channelIndex, fNominalFrequency, tc, time, tcalibrated, rotated); |
| scale = fDecimation ? 2 : 1; |
| if (!IsTimingCalibrationValid() || !tcalibrated) { |
| double t0 = tc / fNominalFrequency; |
| for (i = 0; i < fChannelDepth; i++) { |
| if (rotated) |
| time[i] = static_cast < float >(((i*scale+tc) % kNumberOfBins) / fNominalFrequency - t0); |
| else |
| time[i] = static_cast < float >((i*scale) / fNominalFrequency); |
| if (time[i] < 0) |
| time[i] += static_cast < float > (kNumberOfBins / fNominalFrequency); |
| if (i*scale >= kNumberOfBins) |
| time[i] += static_cast < float > (kNumberOfBins / fNominalFrequency); |
| } |
| return 1; |
| } |
| time[0] = 0; |
| for (i=1 ; i<fChannelDepth ; i++) { |
| if (rotated) |
| time[i] = time[i-1] + (float)fCellDT[chipIndex][channelIndex][(i-1+tc) % kNumberOfBins]; |
| else |
| time[i] = time[i-1] + (float)fCellDT[chipIndex][channelIndex][(i-1) % kNumberOfADCBins]; |
| } |
| if (channelIndex > 0) { |
| // correct all channels to channel 0 (Daniel's method) |
| iend = tc >= 700 ? 700+1024 : 700; |
| for (i=tc,gt0=0 ; i<iend ; i++) |
| gt0 += fCellDT[chipIndex][0][i % 1024]; |
| for (i=tc,gt=0 ; i<iend ; i++) |
| gt += fCellDT[chipIndex][channelIndex][i % 1024]; |
| for (i=0 ; i<fChannelDepth ; i++) |
| time[i] += (float)(gt0 - gt); |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::GetTimeCalibration(unsigned int chipIndex, int channelIndex, int mode, float *time, bool force) |
| { |
| int i; |
| float tint; |
| /* not implemented for DRS2 */ |
| if (fDRSType < 4) |
| return -1; |
| if (!force && !IsTimingCalibrationValid()) { |
| for (i = 0; i < kNumberOfBins; i++) |
| time[i] = (float) (1/fNominalFrequency); |
| return 1; |
| } |
| if (mode == 0) { |
| /* differential nonlinearity */ |
| for (i=0 ; i<kNumberOfBins ; i++) |
| time[i] = static_cast < float > (fCellDT[chipIndex][channelIndex][i]); |
| } else { |
| /* integral nonlinearity */ |
| for (i=0,tint=0; i<kNumberOfBins ; i++) { |
| time[i] = static_cast < float > (tint - i/fNominalFrequency); |
| tint += (float)fCellDT[chipIndex][channelIndex][i]; |
| } |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::GetTime(unsigned int chipIndex, int channelIndex, double freqGHz, int tc, float *time, bool tcalibrated, bool rotated) |
| { |
| /* for DRS4, use function above */ |
| if (fDRSType == 4) |
| return GetTime(chipIndex, channelIndex, tc, time, tcalibrated, rotated); |
| int i, irot; |
| DRSBoard::TimeData * init; |
| DRSBoard::TimeData::FrequencyData * freq; |
| int frequencyMHz = (int)(freqGHz*1000); |
| init = GetTimeCalibration(chipIndex); |
| if (init == NULL) { |
| for (i = 0; i < kNumberOfBins; i++) |
| time[i] = static_cast < float >(i / fNominalFrequency); |
| return 1; |
| } |
| freq = NULL; |
| for (i = 0; i < init->fNumberOfFrequencies; i++) { |
| if (init->fFrequency[i]->fFrequency == frequencyMHz) { |
| freq = init->fFrequency[i]; |
| break; |
| } |
| } |
| if (freq == NULL) { |
| for (i = 0; i < kNumberOfBins; i++) |
| time[i] = static_cast < float >(i / fNominalFrequency); |
| return 1; |
| } |
| for (i = 0; i < kNumberOfBins; i++) { |
| irot = (fStopCell[chipIndex] + i) % kNumberOfBins; |
| if (fStopCell[chipIndex] + i < kNumberOfBins) |
| time[i] = static_cast < float >((freq->fBin[irot] - freq->fBin[fStopCell[chipIndex]]) / fNominalFrequency); |
| else |
| time[i] = |
| static_cast < |
| float |
| >((freq->fBin[irot] - freq->fBin[fStopCell[chipIndex]] + freq->fBin[kNumberOfBins - 1] - 2 * freq->fBin[0] + |
| freq->fBin[1]) / fNominalFrequency); |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| bool DRSBoard::InitTimeCalibration(unsigned int chipIndex) |
| { |
| return GetTimeCalibration(chipIndex, true) != NULL; |
| } |
| /*------------------------------------------------------------------*/ |
| DRSBoard::TimeData * DRSBoard::GetTimeCalibration(unsigned int chipIndex, bool reinit) |
| { |
| int i, l, index; |
| char *cstop; |
| char fileName[500]; |
| char error[240]; |
| PMXML_NODE node, rootNode, mainNode; |
| index = fNumberOfTimeData; |
| for (i = 0; i < fNumberOfTimeData; i++) { |
| if (fTimeData[i]->fChip == static_cast < int >(chipIndex)) { |
| if (!reinit) |
| return fTimeData[i]; |
| else { |
| index = i; |
| break; |
| } |
| } |
| } |
| fTimeData[index] = new DRSBoard::TimeData(); |
| DRSBoard::TimeData * init = fTimeData[index]; |
| init->fChip = chipIndex; |
| for (i = 0; i < init->kMaxNumberOfFrequencies; i++) { |
| if (i <= 499 || (i >= 501 && i <= 999) || (i >= 1001 && i <= 1499) || (i >= 1501 && i <= 1999) || |
| (i >= 2001 && i <= 2499) || i >= 2501) |
| continue; |
| sprintf(fileName, "%s/board%d/TimeCalib_board%d_chip%d_%dMHz.xml", fCalibDirectory, fBoardSerialNumber, |
| fBoardSerialNumber, chipIndex, i); |
| rootNode = mxml_parse_file(fileName, error, sizeof(error), NULL); |
| if (rootNode == NULL) |
| continue; |
| init->fFrequency[init->fNumberOfFrequencies] = new DRSBoard::TimeData::FrequencyData(); |
| init->fFrequency[init->fNumberOfFrequencies]->fFrequency = i; |
| mainNode = mxml_find_node(rootNode, "/DRSTimeCalibration"); |
| for (l = 0; l < kNumberOfBins; l++) { |
| node = mxml_subnode(mainNode, l + 2); |
| init->fFrequency[init->fNumberOfFrequencies]->fBin[l] = strtod(mxml_get_value(node), &cstop); |
| } |
| mxml_free_tree(rootNode); |
| init->fNumberOfFrequencies++; |
| } |
| if (init->fNumberOfFrequencies == 0) { |
| printf("Board %d --> Could not find time calibration file\n", GetBoardSerialNumber()); |
| } |
| if (index == fNumberOfTimeData) |
| fNumberOfTimeData++; |
| return fTimeData[index]; |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::SetCalibrationDirectory(const char *calibrationDirectoryPath) |
| { |
| strncpy(fCalibDirectory, calibrationDirectoryPath, strlen(calibrationDirectoryPath)); |
| fCalibDirectory[strlen(calibrationDirectoryPath)] = 0; |
| }; |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::GetCalibrationDirectory(char *calibrationDirectoryPath) |
| { |
| strncpy(calibrationDirectoryPath, fCalibDirectory, strlen(fCalibDirectory)); |
| calibrationDirectoryPath[strlen(fCalibDirectory)] = 0; |
| }; |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::LinearRegression(double *x, double *y, int n, double *a, double *b) |
| { |
| int i; |
| double sx, sxx, sy, sxy; |
| sx = sxx = sy = sxy = 0; |
| for (i = 0; i < n; i++) { |
| sx += x[i]; |
| sxx += x[i] * x[i]; |
| sy += y[i]; |
| sxy += x[i] * y[i]; |
| } |
| *a = (n * sxy - sx * sy) / (n * sxx - sx * sx); |
| *b = (sy - *a * sx) / n; |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::ReadSingleWaveform(int nChip, int nChan, |
| unsigned short wf[kNumberOfChipsMax][kNumberOfChannelsMax][kNumberOfBins], |
| bool rotated) |
| { |
| int i, j, k, tc; |
| StartDomino(); |
| SoftTrigger(); |
| while (IsBusy()); |
| TransferWaves(); |
| for (i=0 ; i<nChip ; i++) { |
| tc = GetTriggerCell(i); |
| for (j=0 ; j<nChan ; j++) { |
| GetRawWave(i, j, wf[i][j], rotated); |
| if (!rotated) { |
| for (k=0 ; k<kNumberOfBins ; k++) { |
| /* do primary offset calibration */ |
| wf[i][j][k] = wf[i][j][k] - fCellOffset[j+i*9][(k + tc) % kNumberOfBins] + 32768; |
| } |
| } |
| } |
| } |
| } |
| static unsigned short swf[kNumberOfChipsMax][kNumberOfChannelsMax][kNumberOfBins]; |
| static float center[kNumberOfChipsMax][kNumberOfChannelsMax][kNumberOfBins]; |
| int DRSBoard::AverageWaveforms(DRSCallback *pcb, int nChip, int nChan, |
| int prog1, int prog2, unsigned short *awf, int n, bool rotated) |
| { |
| int i, j, k, l, prog, old_prog = 0; |
| float cm; |
| if (pcb != NULL) |
| pcb->Progress(prog1); |
| memset(center, 0, sizeof(center)); |
| for (i=0 ; i<n; i++) { |
| ReadSingleWaveform(nChip, nChan, swf, rotated); |
| for (j=0 ; j<nChip ; j++) { |
| for (k=0 ; k<nChan ; k++) { |
| if (i > 5) { |
| /* calculate and subtract common mode */ |
| for (l=0,cm=0 ; l<kNumberOfBins ; l++) |
| cm += swf[j][k][l] - 32768; |
| cm /= kNumberOfBins; |
| for (l=0 ; l<kNumberOfBins ; l++) |
| center[j][k][l] += swf[j][k][l]- cm; |
| } |
| } |
| } |
| prog = (int)(((double)i/n)*(prog2-prog1)+prog1); |
| if (prog > old_prog) { |
| old_prog = prog; |
| if (pcb != NULL) |
| pcb->Progress(prog); |
| } |
| } |
| for (i=0 ; i<nChip ; i++) |
| for (j=0 ; j<nChan ; j++) |
| for (k=0 ; k<kNumberOfBins ; k++) |
| awf[(i*nChan+j)*kNumberOfBins+k] = (unsigned short)(center[i][j][k]/(n-6) + 0.5); |
| return 1; |
| } |
| int DRSBoard::RobustAverageWaveforms(DRSCallback *pcb, int nChip, int nChan, |
| int prog1, int prog2, unsigned short *awf, int n, bool rotated) |
| { |
| int i, j, k, l, prog, old_prog = 0; |
| if (pcb != NULL) |
| pcb->Progress(prog1); |
| Averager *ave = new Averager(nChip, nChan, kNumberOfBins, 200); |
| /* fill histograms */ |
| for (i=0 ; i<n ; i++) { |
| ReadSingleWaveform(nChip, nChan, swf, rotated); |
| for (j=0 ; j<nChip ; j++) |
| for (k=0 ; k<nChan ; k++) |
| for (l=0 ; l<kNumberOfBins ; l++) |
| ave->Add(j, k, l, swf[j][k][l]); |
| /* update progress bar */ |
| prog = (int)(((double)(i+10)/(n+10))*(prog2-prog1)+prog1); |
| if (prog > old_prog) { |
| old_prog = prog; |
| if (pcb != NULL) |
| pcb->Progress(prog); |
| } |
| } |
| /* |
| FILE *fh = fopen("calib.csv", "wt"); |
| for (i=40 ; i<60 ; i++) { |
| for (j=0 ; j<WFH_SIZE ; j++) |
| fprintf(fh, "%d;", wfh[0][0][i][j]); |
| fprintf(fh, "\n"); |
| } |
| fclose(fh); |
| */ |
| for (i=0 ; i<nChip ; i++) |
| for (j=0 ; j<nChan ; j++) |
| for (k=0 ; k<kNumberOfBins ; k++) |
| awf[(i*nChan+j)*kNumberOfBins+k] = (unsigned short)ave->RobustAverage(100, i, j, k); |
| ave->SaveNormalizedDistribution("wv.csv", 0, 100); |
| /* |
| FILE *fh = fopen("calib.csv", "wt"); |
| for (i=40 ; i<60 ; i++) { |
| fprintf(fh, "%d;", icenter[0][0][0] + (i - WFH_SIZE/2)*16); |
| fprintf(fh, "%d;", wfh[0][0][0][i]); |
| if (i == 50) |
| fprintf(fh, "%d;", awf[0]); |
| fprintf(fh, "\n"); |
| } |
| fclose(fh); |
| */ |
| if (pcb != NULL) |
| pcb->Progress(prog2); |
| delete ave; |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int idx[4][10] = { |
| { 0, 2, 4, 6, 8, 18, 20, 22, 24, 26 }, |
| { 1, 3, 5, 7, 39, 19, 21, 23, 25, 39 }, |
| { 9, 11, 13, 15, 17, 27, 29, 31, 33, 35 }, |
| { 10, 12, 14, 16, 39, 28, 30, 32, 34, 39 }, |
| }; |
| #define F1(x) ((int) (84.0/24 * (x))) |
| #define F2(x) ((int) (92.0/8 * (x))) |
| static unsigned short wft[kNumberOfChipsMax*kNumberOfChannelsMax*kNumberOfChipsMax][1024], |
| wf1[kNumberOfChipsMax*kNumberOfChannelsMax*kNumberOfChipsMax][1024], |
| wf2[kNumberOfChipsMax*kNumberOfChannelsMax*kNumberOfChipsMax][1024], |
| wf3[kNumberOfChipsMax*kNumberOfChannelsMax*kNumberOfChipsMax][1024]; |
| int DRSBoard::CalibrateVolt(DRSCallback *pcb) |
| { |
| int i, j, nChan, timingChan, chip, config, p, clkon, refclk, trg1, trg2, n_stuck, readchn, casc; |
| double f, r; |
| unsigned short buf[1024*16]; // 32 kB |
| f = fNominalFrequency; |
| r = fRange; |
| clkon = (GetCtrlReg() & BIT_TCAL_EN) > 0; |
| refclk = (GetCtrlReg() & BIT_REFCLK_SOURCE) > 0; |
| trg1 = fTriggerEnable1; |
| trg2 = fTriggerEnable2; |
| readchn = fNumberOfReadoutChannels; |
| casc = fChannelCascading; |
| Init(); |
| fNominalFrequency = f; |
| SetRefclk(refclk); |
| SetFrequency(fNominalFrequency, true); |
| SetDominoMode(1); |
| SetDominoActive(1); |
| SetReadoutMode(1); |
| SetInputRange(r); |
| if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) |
| SelectClockSource(0); |
| else if (fBoardType == 6) |
| SetRefclk(refclk); |
| EnableTrigger(0, 0); |
| if (readchn == 5) |
| SetChannelConfig(4, 8, 8); // even channel readout mode |
| // WSROUT toggling causes some noise, so calibrate that out |
| if (casc == 2) { |
| if (fTransport == TR_USB2) |
| SetChannelConfig(0, 8, 4); |
| else |
| SetChannelConfig(7, 8, 4); |
| } |
| StartDomino(); |
| nChan = 0; |
| timingChan = 0; |
| if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) { |
| if (fBoardType == 9) { |
| nChan = 8; |
| timingChan = -1; |
| } else { |
| nChan = 9; |
| timingChan = 8; |
| } |
| /* measure offset */ |
| if (fBoardType == 5) |
| EnableAcal(0, 0); // no inputs signal is allowed during calibration! |
| else |
| EnableAcal(1, 0); // disconnect analog inputs |
| EnableTcal(0, 0); |
| Sleep(100); |
| RobustAverageWaveforms(pcb, 1, nChan, 0, 25, wf1[0], 200, true); |
| /* measure gain at upper range */ |
| EnableAcal(1, fRange+0.4); |
| EnableTcal(0, 1); |
| Sleep(100); |
| RobustAverageWaveforms(pcb, 1, nChan, 25, 50, wf2[0], 200, true); |
| } else if (fBoardType == 6) { |
| if (fTransport == TR_USB2) { |
| nChan = 36; |
| timingChan = 8; |
| memset(wf1, 0, sizeof(wf1)); |
| memset(wf2, 0, sizeof(wf2)); |
| memset(wf3, 0, sizeof(wf3)); |
| for (config=p=0 ; config<4 ; config++) { |
| SetChannelConfig(config, 8, 8); |
| /* measure offset */ |
| EnableAcal(1, 0); |
| EnableTcal(0, 0); |
| Sleep(100); |
| RobustAverageWaveforms(pcb, 0, 10, F1(p), F1(p+1), wft[0], 500, true); p++; |
| for (i=0 ; i<5 ; i++) |
| memcpy(wf1[idx[config][i]], wft[i*2], sizeof(float)*kNumberOfBins); |
| RobustAverageWaveforms(pcb, 2, 10, F1(p), F1(p+1), wft[0], 500, true); p++; |
| for (i=0 ; i<5 ; i++) |
| memcpy(wf1[idx[config][i+5]], wft[i*2], sizeof(float)*kNumberOfBins); |
| /* measure gain at +400 mV */ |
| EnableAcal(1, 0.4); |
| EnableTcal(0, 0); |
| Sleep(100); |
| RobustAverageWaveforms(pcb, 0, 8, F1(p), F1(p+1), wft[0], 500, true); p++; |
| for (i=0 ; i<4 ; i++) |
| memcpy(wf2[idx[config][i]], wft[i*2], sizeof(float)*kNumberOfBins); |
| RobustAverageWaveforms(pcb, 2, 8, F1(p), F1(p+1), wft[0], 500, true); p++; |
| for (i=0 ; i<4 ; i++) |
| memcpy(wf2[idx[config][i+5]], wft[i*2], sizeof(float)*kNumberOfBins); |
| /* measure gain at -400 mV */ |
| EnableAcal(1, -0.4); |
| EnableTcal(0, 1); |
| Sleep(100); |
| RobustAverageWaveforms(pcb, 0, 8, F1(p), F1(p+1), wft[0], 500, true); p++; |
| for (i=0 ; i<4 ; i++) |
| memcpy(wf3[idx[config][i]], wft[i], sizeof(float)*kNumberOfBins); |
| RobustAverageWaveforms(pcb, 2, 8, F1(p), F1(p+1), wft[0], 500, true); p++; |
| for (i=0 ; i<4 ; i++) |
| memcpy(wf3[idx[config][i+5]], wft[i], sizeof(float)*kNumberOfBins); |
| } |
| } else { |
| nChan = 36; |
| timingChan = 8; |
| /* measure offset */ |
| EnableAcal(0, 0); // no inputs signal is allowed during calibration! |
| EnableTcal(0, 0); |
| Sleep(100); |
| RobustAverageWaveforms(pcb, 4, 9, 0, 25, wf1[0], 500, true); |
| /* measure gain at upper range */ |
| EnableAcal(1, fRange+0.4); |
| EnableTcal(0, 0); |
| Sleep(100); |
| RobustAverageWaveforms(pcb, 4, 9, 25, 50, wf2[0], 500, true); |
| } |
| } |
| /* convert offsets and gains to 16-bit values */ |
| memset(fCellOffset, 0, sizeof(fCellOffset)); |
| n_stuck = 0; |
| for (i=0 ; i<nChan ; i++) { |
| for (j=0 ; j<kNumberOfBins; j++) { |
| if (i % 9 == timingChan) { |
| /* calculate offset and gain for timing channel */ |
| if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) { |
| /* we have a +325mV and a -325mV value */ |
| fCellOffset[i][j] = (unsigned short) ((wf1[i][j]+wf2[i][j])/2+0.5); |
| fCellGain[i][j] = (wf2[i][j] - wf1[i][j])/65536.0*1000 / 650.0; |
| } else { |
| /* only have offset */ |
| fCellOffset[i][j] = wf1[i][j]; |
| fCellGain[i][j] = 1; |
| } |
| } else { |
| /* calculate offset and gain for data channel */ |
| fCellOffset[i][j] = wf1[i][j]; |
| if (fCellOffset[i][j] < 100) { |
| // mark stuck pixel |
| n_stuck ++; |
| fCellOffset[i][j] = 0; |
| fCellGain[i][j] = 1; |
| } else |
| fCellGain[i][j] = (wf2[i][j] - fCellOffset[i][j])/65536.0*1000 / ((0.4+fRange)*1000); |
| } |
| /* check gain */ |
| if (fCellGain[i][j] < 0.5 || fCellGain[i][j] > 1.1) { |
| if ((fBoardType == 7 || fBoardType == 8 || fBoardType == 9) && i % 2 == 1) { |
| /* channels are not connected, so don't print error */ |
| } else { |
| printf("Gain of %6.3lf for channel %2d, cell %4d out of range 0.5 ... 1.1\n", |
| fCellGain[i][j], i, j); |
| } |
| fCellGain[i][j] = 1; |
| } |
| } |
| } |
| /* |
| FILE *fh = fopen("calib.txt", "wt"); |
| for (i=0 ; i<nChan ; i++) { |
| fprintf(fh, "CH%02d:", i); |
| for (j=0 ; j<20 ; j++) |
| fprintf(fh, " %5d", fCellOffset[i][j]-32768); |
| fprintf(fh, "\n"); |
| } |
| fclose(fh); |
| */ |
| /* perform secondary calibration */ |
| if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8 || fBoardType == 9) { |
| nChan = 9; |
| timingChan = 8; |
| /* measure offset */ |
| if (fBoardType == 5) |
| EnableAcal(0, 0); // no inputs signal is allowed during calibration! |
| else |
| EnableAcal(1, 0); // disconnect analog inputs |
| EnableTcal(0, 0); |
| Sleep(100); |
| AverageWaveforms(pcb, 1, 9, 50, 90, wf1[0], 500, false); |
| } else if (fBoardType == 6 && fTransport == TR_VME) { |
| nChan = 36; |
| timingChan = 8; |
| /* measure offset */ |
| EnableAcal(0, 0); // no inputs signal is allowed during calibration! |
| EnableTcal(0, 0); |
| Sleep(100); |
| AverageWaveforms(pcb, 4, 9, 50, 75, wf1[0], 500, false); |
| } |
| /* convert offset to 16-bit values */ |
| memset(fCellOffset2, 0, sizeof(fCellOffset2)); |
| for (i=0 ; i<nChan ; i++) |
| for (j=0 ; j<kNumberOfBins; j++) |
| if (i % 9 != timingChan) |
| fCellOffset2[i][j] = wf1[i][j]; |
| /* |
| FILE *fh = fopen("calib.txt", "wt"); |
| for (i=0 ; i<nChan ; i++) { |
| for (j=0 ; j<kNumberOfBins; j++) |
| fprintf(fh, "%5d: %5d %5d\n", j, fCellOffset2[0][j]-32768, fCellOffset2[1][j]-32768); |
| fprintf(fh, "\n"); |
| } |
| fclose(fh); |
| */ |
| if (fBoardType == 9) { |
| /* write calibration CH0-CH7 to EEPROM page 1 */ |
| for (i=0 ; i<8 ; i++) |
| for (j=0 ; j<1024; j++) { |
| buf[(i*1024+j)*2] = fCellOffset[i][j]; |
| buf[(i*1024+j)*2+1] = (unsigned short) ((fCellGain[i][j] - 0.7) / 0.4 * 65535); |
| } |
| WriteEEPROM(1, buf, 1024*32); |
| if (pcb != NULL) |
| pcb->Progress(93); |
| /* write secondary calibration to EEPROM page 2 */ |
| ReadEEPROM(2, buf, 1024*32); |
| for (i=0 ; i<8 ; i++) |
| for (j=0 ; j<1024; j++) |
| buf[(i*1024+j)*2] = fCellOffset2[i][j]; |
| WriteEEPROM(2, buf, 1024*32); |
| if (pcb != NULL) |
| pcb->Progress(96); |
| /* update page # 0 */ |
| ReadEEPROM(0, buf, 4096); // 0-0x0FFF |
| /* write calibration method */ |
| buf[2] = (buf[2] & 0xFF00) | VCALIB_METHOD; |
| /* write temperature and range */ |
| buf[10] = ((unsigned short) (GetTemperature() * 2 + 0.5) << 8) | ((signed char)(fRange * 100)); |
| buf[11] = 1; // EEPROM page #1+2 |
| WriteEEPROM(0, buf, 4096); |
| fCellCalibratedRange = fRange; |
| if (pcb != NULL) |
| pcb->Progress(100); |
| } else if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8) { |
| /* write calibration CH0-CH7 to EEPROM page 1 */ |
| for (i=0 ; i<8 ; i++) |
| for (j=0 ; j<1024; j++) { |
| buf[(i*1024+j)*2] = fCellOffset[i][j]; |
| buf[(i*1024+j)*2+1] = (unsigned short) ((fCellGain[i][j] - 0.7) / 0.4 * 65535); |
| } |
| WriteEEPROM(1, buf, 1024*32); |
| /* write calibration CH8 and secondary calibration to EEPROM page 2 */ |
| for (j=0 ; j<1024; j++) { |
| buf[j*2] = fCellOffset[8][j]; |
| buf[j*2+1] = (unsigned short) ((fCellGain[8][j] - 0.7) / 0.4 * 65535); |
| } |
| for (i=0 ; i<4 ; i++) |
| for (j=0 ; j<1024; j++) { |
| buf[2*1024+(i*1024+j)*2] = fCellOffset2[i*2][j]; |
| buf[2*1024+(i*1024+j)*2+1] = fCellOffset2[i*2+1][j]; |
| } |
| WriteEEPROM(2, buf, 1024*5*4); |
| /* write calibration method and range */ |
| ReadEEPROM(0, buf, 2048); // 0-0x0FFF |
| buf[2] = VCALIB_METHOD_V4 | ((signed char)(fRange * 100)) << 8; |
| WriteEEPROM(0, buf, 2048); |
| fCellCalibratedRange = fRange; |
| } else if (fBoardType == 6) { |
| for (chip=0 ; chip<4 ; chip++) { |
| /* write calibration of A0 to A7 to EEPROM page 1 |
| B0 to B7 to EEPROM page 2 and so on */ |
| for (i=0 ; i<8 ; i++) |
| for (j=0 ; j<1024; j++) { |
| buf[(i*1024+j)*2] = fCellOffset[i+chip*9][j]; |
| buf[(i*1024+j)*2+1] = (unsigned short) ((fCellGain[i+chip*9][j] - 0.7) / 0.4 * 65535); |
| } |
| WriteEEPROM(1+chip, buf, 1024*32); |
| if (pcb != NULL) |
| pcb->Progress(75+chip*4); |
| } |
| /* write calibration A/B/C/D/CLK to EEPROM page 5 */ |
| ReadEEPROM(5, buf, 1024*4*4); |
| for (chip=0 ; chip<4 ; chip++) { |
| for (j=0 ; j<1024; j++) { |
| buf[j*2+chip*0x0800] = fCellOffset[8+chip*9][j]; |
| buf[j*2+1+chip*0x0800] = (unsigned short) ((fCellGain[8+chip*9][j] - 0.7) / 0.4 * 65535); |
| } |
| } |
| WriteEEPROM(5, buf, 1024*4*4); |
| if (pcb != NULL) |
| pcb->Progress(90); |
| /* write secondary calibration to EEPROM page 7 and 8 */ |
| for (i=0 ; i<8 ; i++) { |
| for (j=0 ; j<1024; j++) { |
| buf[i*0x800 + j*2] = fCellOffset2[i][j]; |
| buf[i*0x800 + j*2+1] = fCellOffset2[i+9][j]; |
| } |
| } |
| WriteEEPROM(7, buf, 1024*32); |
| if (pcb != NULL) |
| pcb->Progress(94); |
| for (i=0 ; i<8 ; i++) { |
| for (j=0 ; j<1024; j++) { |
| buf[i*0x800 + j*2] = fCellOffset2[i+18][j]; |
| buf[i*0x800 + j*2+1] = fCellOffset2[i+27][j]; |
| } |
| } |
| WriteEEPROM(8, buf, 1024*32); |
| if (pcb != NULL) |
| pcb->Progress(98); |
| /* write calibration method and range */ |
| ReadEEPROM(0, buf, 2048); // 0-0x0FFF |
| buf[2] = VCALIB_METHOD | ((signed char)(fRange * 100)) << 8; |
| WriteEEPROM(0, buf, 2048); |
| fCellCalibratedRange = fRange; |
| if (pcb != NULL) |
| pcb->Progress(100); |
| } |
| if (n_stuck) |
| printf("\nFound %d stuck pixels on this board\n", n_stuck); |
| fVoltageCalibrationValid = true; |
| /* remove calibration voltage */ |
| EnableAcal(0, 0); |
| EnableTcal(clkon, 0); |
| EnableTrigger(trg1, trg2); |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::AnalyzeSlope(Averager *ave, int iIter, int nIter, int channel, float wf[kNumberOfBins], int tCell, |
| double cellDV[kNumberOfBins], double cellDT[kNumberOfBins]) |
| { |
| int i; |
| float dv, llim, ulim; |
| double sum, dtCell; |
| if (fNominalFrequency > 3) { |
| llim = -100; |
| ulim = 100; |
| } else { |
| llim = -300; |
| ulim = 300; |
| } |
| // rising edges ---- |
| // skip first cells after trigger cell |
| for (i=tCell+5 ; i<tCell+kNumberOfBins-5 ; i++) { |
| // test slope between previous and next cell to allow for negative cell width |
| if (wf[(i+kNumberOfBins-1) % kNumberOfBins] < wf[(i+2) % kNumberOfBins] && |
| wf[i % kNumberOfBins] > llim && |
| wf[(i+1) % kNumberOfBins] < ulim) { |
| // calculate delta_v |
| dv = wf[(i+1) % kNumberOfBins] - wf[i % kNumberOfBins]; |
| // average delta_v |
| ave->Add(0, channel, i % kNumberOfBins, dv); |
| } |
| } |
| // falling edges ---- |
| // skip first cells after trigger cell |
| for (i=tCell+5 ; i<tCell+kNumberOfBins-5 ; i++) { |
| // test slope between previous and next cell to allow for negative cell width |
| if (wf[(i+kNumberOfBins-1) % kNumberOfBins] > wf[(i+2) % kNumberOfBins] && |
| wf[i % kNumberOfBins] < ulim && |
| wf[(i+1) % kNumberOfBins] > llim) { |
| // calcualte delta_v |
| dv = wf[(i+1) % kNumberOfBins] - wf[i % kNumberOfBins]; |
| ave->Add(0, channel, i % kNumberOfBins, -dv); |
| } |
| } |
| // calculate calibration every 100 events |
| if ((iIter + 1) % 100 == 0) { |
| // average over all 1024 dU |
| sum = 0; |
| for (i=0 ; i<kNumberOfBins ; i++) { |
| if (fBoardType == 8) |
| cellDV[i] = ave->Median(0, channel, i); |
| else { |
| // use empirically found limits for averaging |
| if (fNominalFrequency >= 4) |
| cellDV[i] = ave->RobustAverage(3, 0, channel, i); |
| else if (fNominalFrequency >= 3) |
| cellDV[i] = ave->RobustAverage(6, 0, channel, i); |
| else |
| cellDV[i] = ave->Median(0, channel, i); |
| } |
| sum += cellDV[i]; |
| } |
| sum /= kNumberOfBins; |
| dtCell = (float)1/fNominalFrequency; |
| // here comes the central calculation, dT = dV/average * dt_cell |
| for (i=0 ; i<kNumberOfBins ; i++) |
| cellDT[i] = cellDV[i] / sum * dtCell; |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::AnalyzePeriod(Averager *ave, int iIter, int nIter, int channel, float wf[kNumberOfBins], int tCell, |
| double cellDV[kNumberOfBins], double cellDT[kNumberOfBins]) |
| { |
| int i, i1, i2, j, nzx, zeroXing[1000], edge, n_correct, nest; |
| double damping, zeroLevel, tPeriod, corr, dv, dv_limit, corr_limit; |
| /* calculate zero level */ |
| for (i=0,zeroLevel=0 ; i<1024 ; i++) |
| zeroLevel += wf[i]; |
| zeroLevel /= 1024; |
| /* correct for zero common mode */ |
| for (i=0 ; i<1024 ; i++) |
| wf[i] -= (float)zeroLevel; |
| /* estimate damping factor */ |
| if (fBoardType == 9) |
| damping = 0.01; |
| else |
| damping = fNominalFrequency / nIter * 2 ; |
| /* estimate number of zero crossings */ |
| nest = (int) (1/fNominalFrequency*1024 / (1/fTCALFrequency*1000)); |
| if (fNominalFrequency >= 4) |
| dv_limit = 4; |
| else if (fNominalFrequency >= 3) |
| dv_limit = 6; |
| else |
| dv_limit = 10000; |
| for (edge = 0 ; edge < 2 ; edge ++) { |
| /* find edge zero crossing with wrap-around */ |
| for (i=tCell+5,nzx=0 ; i<tCell+1023-5 && nzx < (int)(sizeof(zeroXing)/sizeof(int)) ; i++) { |
| dv = fabs(wf[(i+1) % 1024] - wf[i % 1024]); |
| if (edge == 0) { |
| if (wf[(i+1) % 1024] < 0 && wf[i % 1024] > 0) { // falling edge |
| if (fBoardType != 9 || fabs(dv-cellDV[i % 1024]) < dv_limit) // only if DV is not more the dv_limit away from average |
| zeroXing[nzx++] = i % 1024; |
| } |
| } else { |
| if (wf[(i+1) % 1024] > 0 && wf[i % 1024] < 0) { // rising edge |
| if (fBoardType != 9 || fabs(dv-cellDV[i % 1024]) < dv_limit) |
| zeroXing[nzx++] = i % 1024; |
| } |
| } |
| } |
| /* abort if uncorrect number of edges is found */ |
| if (abs(nest - nzx) > nest / 3) |
| return 0; |
| for (i=n_correct=0 ; i<nzx-1 ; i++) { |
| i1 = zeroXing[i]; |
| i2 = zeroXing[i+1]; |
| if (i1 == 1023 || i2 == 1023) |
| continue; |
| if (wf[(i1 + 1) % 1024] == 0 || wf[i2 % 1024] == 0) |
| continue; |
| /* first partial cell */ |
| tPeriod = cellDT[i1]*(1/(1-wf[i1]/wf[(i1 + 1) % 1024])); |
| /* full cells between i1 and i2 */ |
| if (i2 < i1) |
| i2 += 1024; |
| for (j=i1+1 ; j<i2 ; j++) |
| tPeriod += cellDT[j % 1024]; |
| /* second partial cell */ |
| tPeriod += cellDT[i2 % 1024]*(1/(1-wf[(i2+1) % 1024]/wf[i2 % 1024])); |
| /* calculate correction to nominal period as a fraction */ |
| corr = (1/fTCALFrequency*1000) / tPeriod; |
| /* skip very large corrections (noise) */ |
| if (fBoardType == 9 && fNominalFrequency >= 2) |
| corr_limit = 0.001; |
| else if (fBoardType == 9) |
| corr_limit = 0.004; |
| else |
| corr_limit = 0.01; |
| if (fBoardType == 9 && fabs(1-corr) > corr_limit) |
| continue; |
| /* remeber number of valid corrections */ |
| n_correct++; |
| /* apply damping factor */ |
| corr = (corr-1)*damping + 1; |
| /* apply from i1 to i2-1 inclusive */ |
| if (i1 == i2) |
| continue; |
| /* distribute correciton equally into bins inside the region ... */ |
| for (j=i1 ; j<=i2 ; j++) |
| cellDT[j % 1024] *= corr; |
| /* test correction */ |
| tPeriod = cellDT[i1]*(1/(1-wf[i1]/wf[(i1 + 1) % 1024])); |
| for (j=i1+1 ; j<i2 ; j++) |
| tPeriod += cellDT[j % 1024]; |
| tPeriod += cellDT[i2]*(1/(1-wf[(i2+1) % 1024]/wf[i2])); |
| } |
| if (n_correct < nzx/3) |
| return 0; |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int DRSBoard::CalibrateTiming(DRSCallback *pcb) |
| { |
| int index, status, error, tCell, i, j, c, chip, mode, nIterPeriod, nIterSlope, clkon, phase, refclk, trg1, trg2, n_error, channel; |
| double f, range, tTrue, tRounded, dT, t1[8], t2[8], cellDV[kNumberOfChipsMax*kNumberOfChannelsMax][kNumberOfBins]; |
| unsigned short buf[1024*16]; // 32 kB |
| float wf[1024]; |
| Averager *ave = NULL; |
| nIterPeriod = 5000; |
| nIterSlope = 5000; |
| n_error = 0; |
| refclk = 0; |
| f = fNominalFrequency; |
| range = fRange; |
| clkon = (GetCtrlReg() & BIT_TCAL_EN) > 0; |
| if (fBoardType == 6) |
| refclk = (GetCtrlReg() & BIT_REFCLK_SOURCE) > 0; |
| trg1 = fTriggerEnable1; |
| trg2 = fTriggerEnable2; |
| Init(); |
| fNominalFrequency = f; |
| fTimingCalibratedFrequency = 0; |
| if (fBoardType == 6) // don't set refclk for evaluation boards |
| SetRefclk(refclk); |
| SetFrequency(fNominalFrequency, true); |
| if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8) |
| fTCALFrequency = 132; // 132 MHz for EVAL1, for MEZZ this is set by ConfigureLMK |
| else if (fBoardType == 9) |
| fTCALFrequency = 100; |
| SetDominoMode(1); |
| SetDominoActive(1); |
| SetReadoutMode(1); |
| EnableTrigger(0, 0); |
| if (fBoardType == 5 || fBoardType == 7) { |
| EnableTcal(1, 0, 0); |
| SelectClockSource(1); // 2nd quartz |
| } else if (fBoardType == 8) { |
| nIterSlope = 0; |
| nIterPeriod = 1500; |
| EnableTcal(1, 0, 0); |
| SelectClockSource(1); // 2nd quartz |
| ave = new Averager(1, 1, 1024, 500); // one chip, 1 channel @ 1024 bins |
| } else if (fBoardType == 9) { |
| EnableTcal(1); |
| nIterSlope = 500; |
| nIterPeriod = 500; |
| ave = new Averager(1, 9, 1024, 500); // one chip, 9 channels @ 1024 bins |
| } |
| StartDomino(); |
| /* initialize time array */ |
| for (i=0 ; i<1024 ; i++) |
| for (chip=0 ; chip<4 ; chip++) |
| for (channel = 0 ; channel < 8 ; channel++) { |
| fCellDT[chip][channel][i] = (float)1/fNominalFrequency; // [ns] |
| } |
| error = 0; |
| for (index = 0 ; index < nIterSlope+nIterPeriod ; index++) { |
| if (index % 10 == 0) |
| if (pcb) |
| pcb->Progress(100*index/(nIterSlope+nIterPeriod)); |
| if (fTransport == TR_VME) { |
| SoftTrigger(); |
| while (IsBusy()); |
| /* select random phase */ |
| phase = (rand() % 30) - 15; |
| if (phase == 0) |
| phase = 15; |
| EnableTcal(1, 0, phase); |
| StartDomino(); |
| TransferWaves(); |
| for (chip=0 ; chip<4 ; chip++) { |
| tCell = GetStopCell(chip); |
| GetWave(chip, 8, wf, true, tCell, 0, true); |
| status = AnalyzePeriod(ave, index, nIterPeriod, 0, wf, tCell, cellDV[chip], fCellDT[chip][0]); |
| if (!status) |
| n_error++; |
| if (n_error > nIterPeriod / 10) { |
| error = 1; |
| break; |
| } |
| } |
| } else { |
| if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8) { // DRS4 Evaluation board: 1 Chip |
| SoftTrigger(); |
| while (IsBusy()); |
| StartDomino(); |
| TransferWaves(); |
| tCell = GetStopCell(0); |
| GetWave(0, 8, wf, true, tCell, 0, true); |
| if (index < nIterSlope) |
| status = AnalyzeSlope(ave, index, nIterSlope, 0, wf, tCell, cellDV[0], fCellDT[0][0]); |
| else |
| status = AnalyzePeriod(ave, index, nIterPeriod, 0, wf, tCell, cellDV[0], fCellDT[0][0]); |
| if (!status) |
| n_error++; |
| if (n_error > nIterPeriod / 10) { |
| error = 1; |
| break; |
| } |
| } else if (fBoardType == 9) { // DRS4 Evaluation board V5: all channels from one chip |
| SoftTrigger(); |
| while (IsBusy()); |
| StartDomino(); |
| TransferWaves(); |
| // calibrate all channels individually |
| for (channel = 0 ; channel < 8 ; channel+=2) { |
| tCell = GetStopCell(0); |
| GetWave(0, channel, wf, true, tCell, 0, true); |
| if (index < nIterSlope) |
| status = AnalyzeSlope(ave, index, nIterSlope, channel, wf, tCell, cellDV[channel], fCellDT[0][channel]); |
| else |
| status = AnalyzePeriod(ave, index, nIterPeriod, channel, wf, tCell, cellDV[channel], fCellDT[0][channel]); |
| if (!status) |
| n_error++; |
| if (n_error > nIterPeriod / 2) { |
| error = 1; |
| break; |
| } |
| } |
| if (!status) |
| break; |
| } else { // DRS4 Mezzanine board: 4 Chips |
| for (mode=0 ; mode<2 ; mode++) { |
| SetChannelConfig(mode*2, 8, 8); |
| SoftTrigger(); |
| while (IsBusy()); |
| /* select random phase */ |
| phase = (rand() % 30) - 15; |
| if (phase == 0) |
| phase = 15; |
| EnableTcal(1, 0, phase); |
| StartDomino(); |
| TransferWaves(); |
| for (chip=0 ; chip<4 ; chip+=2) { |
| tCell = GetStopCell(chip+mode); |
| GetWave(chip+mode, 8, wf, true, tCell, 0, true); |
| status = AnalyzePeriod(ave, index, nIterPeriod, 0, wf, tCell, cellDV[chip+mode], fCellDT[chip+mode][0]); |
| if (!status) { |
| error = 1; |
| break; |
| } |
| } |
| if (!status) |
| break; |
| } |
| } |
| } |
| } |
| if (pcb) |
| pcb->Progress(100); |
| // DRS4 Evaluation board V5: copy even channels to odd channels (usually not connected) |
| if (fBoardType == 9) { |
| for (channel = 0 ; channel < 8 ; channel+=2) |
| memcpy(fCellDT[0][channel+1], fCellDT[0][channel], sizeof(unsigned short)*1024); |
| } |
| // use following lines to save calibration into an ASCII file |
| #if 0 |
| FILE *fh; |
| fh = fopen("cellt.csv", "wt"); |
| if (!fh) |
| printf("Cannot open file \"cellt.csv\"\n"); |
| else { |
| fprintf(fh, "index,dt_ch1,dt_ch2,dt_ch3,dt_ch4\n"); |
| for (i=0 ; i<1024 ; i++) |
| fprintf(fh, "%4d,%5.3lf,%5.3lf,%5.3lf,%5.3lf\n", i, fCellDT[0][0][i], fCellDT[0][2][i], fCellDT[0][4][i], fCellDT[0][6][i]); |
| fclose(fh); |
| } |
| #endif |
| if (fBoardType == 5 || fBoardType == 7 || fBoardType == 8) { |
| /* write timing calibration to EEPROM page 0 */ |
| ReadEEPROM(0, buf, sizeof(buf)); |
| for (i=0,t1[0]=0 ; i<1024; i++) |
| buf[i*2+1] = (unsigned short) (fCellDT[0][0][i] * 10000 + 0.5); |
| /* write calibration method and frequency */ |
| buf[4] = TCALIB_METHOD_V4; |
| buf[6] = (unsigned short)(fNominalFrequency*1000+0.5); |
| fTimingCalibratedFrequency = fNominalFrequency; |
| WriteEEPROM(0, buf, sizeof(buf)); |
| // copy calibration to all channels |
| for (i=1 ; i<8 ; i++) |
| for (j=0 ; j<1024; j++) |
| fCellDT[0][i][j] = fCellDT[0][0][j]; |
| } else if (fBoardType == 9) { |
| /* write timing calibration to EEPROM page 2 */ |
| ReadEEPROM(2, buf, sizeof(buf)); |
| for (i=0 ; i<8 ; i++) { |
| tTrue = 0; // true cellT |
| tRounded = 0; // rounded cellT |
| for (j=0 ; j<1024; j++) { |
| tTrue += fCellDT[0][i][j]; |
| dT = tTrue - tRounded; |
| // shift by 1 ns to allow negative widths |
| dT = (unsigned short) (dT*10000+1000+0.5); |
| tRounded += (dT - 1000) / 10000.0; |
| buf[(i*1024+j)*2+1] = (unsigned short) dT; |
| } |
| } |
| WriteEEPROM(2, buf, sizeof(buf)); |
| /* write calibration method and frequency to EEPROM page 0 */ |
| ReadEEPROM(0, buf, sizeof(buf)); |
| buf[4] = 1; // number of calibrations |
| buf[2] = (TCALIB_METHOD << 8) | (buf[2] & 0xFF); // calibration method |
| float fl = (float) fNominalFrequency; |
| memcpy(&buf[8], &fl, sizeof(float)); // exact freqeuncy |
| fTimingCalibratedFrequency = fNominalFrequency; |
| WriteEEPROM(0, buf, sizeof(buf)); |
| } else { |
| /* write timing calibration to EEPROM page 6 */ |
| ReadEEPROM(6, buf, sizeof(buf)); |
| for (c=0 ; c<4 ; c++) |
| t1[c] = 0; |
| for (i=0 ; i<1024; i++) { |
| for (c=0 ; c<4 ; c++) { |
| t2[c] = fCellDT[0][c][i] - t1[c]; |
| t2[c] = (unsigned short) (t2[c] * 10000 + 0.5); |
| t1[c] += t2[c] / 10000.0; |
| } |
| buf[i*2] = (unsigned short) t2[0]; |
| buf[i*2+1] = (unsigned short) t2[1]; |
| buf[i*2+0x800] = (unsigned short) t2[2]; |
| buf[i*2+0x800+1] = (unsigned short) t2[3]; |
| } |
| WriteEEPROM(6, buf, sizeof(buf)); |
| /* write calibration method and frequency */ |
| ReadEEPROM(0, buf, 16); |
| buf[4] = TCALIB_METHOD; |
| buf[6] = (unsigned short) (fNominalFrequency * 1000 + 0.5); |
| fTimingCalibratedFrequency = buf[6] / 1000.0; |
| WriteEEPROM(0, buf, 16); |
| } |
| if (ave) |
| delete ave; |
| /* remove calibration voltage */ |
| EnableAcal(0, 0); |
| EnableTcal(clkon, 0); |
| SetInputRange(range); |
| EnableTrigger(trg1, trg2); |
| if (error) |
| return 0; |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| void DRSBoard::RemoveSymmetricSpikes(short **wf, int nwf, |
| short diffThreshold, int spikeWidth, |
| short maxPeakToPeak, short spikeVoltage, |
| int nTimeRegionThreshold) |
| { |
| // Remove a specific kind of spike on DRS4. |
| // This spike has some features, |
| // - Common on all the channels on a chip |
| // - Constant heigh and width |
| // - Two spikes per channel |
| // - Symmetric to cell #0. |
| // |
| // This is not general purpose spike-removing function. |
| // |
| // wf : Waveform data. cell#0 must be at bin0, |
| // and number of bins must be kNumberOfBins. |
| // nwf : Number of channels which "wf" holds. |
| // diffThreshold : Amplitude threshold to find peak |
| // spikeWidth : Width of spike |
| // maxPeakToPeak : When peak-to-peak is larger than this, the channel |
| // is not used to find spikes. |
| // spikeVoltage : Amplitude of spikes. When it is 0, it is calculated in this function |
| // from voltage difference from neighboring bins. |
| // nTimeRegionThreshold : Requirement of number of time regions having spike at common position. |
| // Total number of time regions is 2*"nwf". |
| if (!wf || !nwf || !diffThreshold || !spikeWidth) { |
| return; |
| } |
| int ibin, jbin, kbin; |
| double v; |
| int nbin; |
| int iwf; |
| short maximum, minimum; |
| int spikeCount[kNumberOfBins / 2]; |
| int spikeCountSum[kNumberOfBins / 2] = {0}; |
| bool largePulse[kNumberOfChannelsMax * 2] = {0}; |
| const short diffThreshold2 = diffThreshold + diffThreshold; |
| const short maxShort = 0xFFFF>>1; |
| const short minShort = -maxShort - 1; |
| // search spike |
| for (iwf = 0; iwf < nwf; iwf++) { |
| // first half |
| memset(spikeCount, 0, sizeof(spikeCount)); |
| maximum = minShort; |
| minimum = maxShort; |
| for (ibin = 0; ibin < kNumberOfBins / 2; ibin++) { |
| jbin = ibin; |
| maximum = max(maximum, wf[iwf][jbin]); |
| minimum = min(minimum, wf[iwf][jbin]); |
| if (jbin - 1 >= 0 && jbin + spikeWidth < kNumberOfBins) { |
| v = 0; |
| nbin = 0; |
| for (kbin = 0; kbin < spikeWidth; kbin++) { |
| v += wf[iwf][jbin + kbin]; |
| nbin++; |
| } |
| if ((nbin == 2 && v - (wf[iwf][jbin - 1] + wf[iwf][jbin + spikeWidth]) > diffThreshold2) || |
| (nbin != 2 && nbin && v / nbin - (wf[iwf][jbin - 1] + wf[iwf][jbin + spikeWidth]) / 2 > diffThreshold)) { |
| spikeCount[ibin]++; |
| } |
| } |
| } |
| if (maximum != minShort && minimum != maxShort && |
| (!maxPeakToPeak || maximum - minimum < maxPeakToPeak)) { |
| for (ibin = 0; ibin < kNumberOfBins / 2; ibin++) { |
| spikeCountSum[ibin] += spikeCount[ibin]; |
| } |
| largePulse[iwf] = false; |
| #if 0 /* this part can be enabled to skip checking other channels */ |
| if (maximum != minShort && minimum != maxShort && |
| maximum - minimum < diffThreshold) { |
| return; |
| } |
| #endif |
| } else { |
| largePulse[iwf] = true; |
| } |
| // second half |
| memset(spikeCount, 0, sizeof(spikeCount)); |
| maximum = minShort; |
| minimum = maxShort; |
| for (ibin = 0; ibin < kNumberOfBins / 2; ibin++) { |
| jbin = kNumberOfBins - 1 - ibin; |
| maximum = max(maximum, wf[iwf][jbin]); |
| minimum = min(minimum, wf[iwf][jbin]); |
| if (jbin + 1 < kNumberOfBins && jbin - spikeWidth >= 0) { |
| v = 0; |
| nbin = 0; |
| for (kbin = 0; kbin < spikeWidth; kbin++) { |
| v += wf[iwf][jbin - kbin]; |
| nbin++; |
| } |
| if ((nbin == 2 && v - (wf[iwf][jbin + 1] + wf[iwf][jbin - spikeWidth]) > diffThreshold2) || |
| (nbin != 2 && nbin && v / nbin - (wf[iwf][jbin + 1] + wf[iwf][jbin - spikeWidth]) / 2 > diffThreshold)) { |
| spikeCount[ibin]++; |
| } |
| } |
| } |
| if (maximum != minShort && minimum != maxShort && |
| maximum - minimum < maxPeakToPeak) { |
| for (ibin = 0; ibin < kNumberOfBins / 2; ibin++) { |
| spikeCountSum[ibin] += spikeCount[ibin]; |
| } |
| largePulse[iwf + nwf] = false; |
| #if 0 /* this part can be enabled to skip checking other channels */ |
| if (maximum != minShort && minimum != maxShort && |
| maximum - minimum < diffThreshold) { |
| return; |
| } |
| #endif |
| } else { |
| largePulse[iwf + nwf] = true; |
| } |
| } |
| // Find common spike |
| int commonSpikeBin = -1; |
| int commonSpikeMax = -1; |
| for (ibin = 0; ibin < kNumberOfBins / 2; ibin++) { |
| if (commonSpikeMax < spikeCountSum[ibin]) { |
| commonSpikeMax = spikeCountSum[ibin]; |
| commonSpikeBin = ibin; |
| } |
| } |
| if (spikeCountSum[commonSpikeBin] >= nTimeRegionThreshold) { |
| if (spikeVoltage == 0) { |
| // Estimate spike amplitude |
| double baseline = 0; |
| int nBaseline = 0; |
| double peakAmplitude = 0; |
| int nPeakAmplitude = 0; |
| for (iwf = 0; iwf < nwf; iwf++) { |
| // first half |
| if (!largePulse[iwf]) { |
| // baseline |
| if ((jbin = commonSpikeBin - 1) >= 0 && jbin < kNumberOfBins) { |
| baseline += wf[iwf][jbin]; |
| nBaseline++; |
| } |
| if ((jbin = commonSpikeBin + spikeWidth + 1) >= 0 && jbin < kNumberOfBins) { |
| baseline += wf[iwf][jbin]; |
| nBaseline++; |
| } |
| // spike |
| for (ibin = 0; ibin < spikeWidth; ibin++) { |
| if ((jbin = commonSpikeBin + ibin) >= 0 && jbin < kNumberOfBins) { |
| peakAmplitude += wf[iwf][jbin]; |
| nPeakAmplitude++; |
| } |
| } |
| } |
| // second half |
| if (!largePulse[iwf + nwf]) { |
| // baseline |
| if ((jbin = kNumberOfBins - 1 - commonSpikeBin + 1) >= 0 && jbin < kNumberOfBins) { |
| baseline += wf[iwf][jbin]; |
| nBaseline++; |
| } |
| if ((jbin = kNumberOfBins - 1 - commonSpikeBin - spikeWidth - 1) >= 0 && jbin < kNumberOfBins) { |
| baseline += wf[iwf][jbin]; |
| nBaseline++; |
| } |
| // spike |
| for (ibin = 0; ibin < spikeWidth; ibin++) { |
| if ((jbin = kNumberOfBins - 1 - commonSpikeBin - ibin) >= 0 && jbin < kNumberOfBins) { |
| peakAmplitude += wf[iwf][jbin]; |
| nPeakAmplitude++; |
| } |
| } |
| } |
| } |
| if (nBaseline && nPeakAmplitude) { |
| baseline /= nBaseline; |
| peakAmplitude /= nPeakAmplitude; |
| spikeVoltage = static_cast<short>(peakAmplitude - baseline); |
| } else { |
| spikeVoltage = 0; |
| } |
| } |
| // Remove spike |
| if (spikeVoltage > 0) { |
| for (iwf = 0; iwf < nwf; iwf++) { |
| for (ibin = 0; ibin < spikeWidth; ibin++) { |
| if ((jbin = commonSpikeBin + ibin) >= 0 && jbin < kNumberOfBins) { |
| wf[iwf][jbin] -= spikeVoltage; |
| } |
| if ((jbin = kNumberOfBins - 1 - commonSpikeBin - ibin) >= 0 && jbin < kNumberOfBins) { |
| wf[iwf][jbin] -= spikeVoltage; |
| } |
| } |
| } |
| } |
| } |
| } |
| /*------------------------------------------------------------------*/ |
| void ResponseCalibration::SetCalibrationParameters(int numberOfPointsLowVolt, int numberOfPoints, |
| int numberOfMode2Bins, int numberOfSamples, |
| int numberOfGridPoints, int numberOfXConstPoints, |
| int numberOfXConstGridPoints, double triggerFrequency, |
| int showStatistics) |
| { |
| DeleteFields(); |
| InitFields(numberOfPointsLowVolt, numberOfPoints, numberOfMode2Bins, numberOfSamples, numberOfGridPoints, |
| numberOfXConstPoints, numberOfXConstGridPoints, triggerFrequency, showStatistics); |
| } |
| /*------------------------------------------------------------------*/ |
| void ResponseCalibration::ResetCalibration() |
| { |
| int i; |
| for (i = 0; i < kNumberOfChipsMax; i++) |
| fCalibrationData[i]->fRead = false; |
| fCurrentPoint = 0; |
| fCurrentLowVoltPoint = 0; |
| fCurrentSample = 0; |
| fCurrentFitChannel = 0; |
| fCurrentFitBin = 0; |
| fRecorded = false; |
| fFitted = false; |
| fOffset = false; |
| }; |
| /*------------------------------------------------------------------*/ |
| bool ResponseCalibration::WriteCalibration(unsigned int chipIndex) |
| { |
| if (!fOffset) |
| return false; |
| if (fBoard->GetDRSType() == 3) |
| return WriteCalibrationV4(chipIndex); |
| else |
| return WriteCalibrationV3(chipIndex); |
| } |
| /*------------------------------------------------------------------*/ |
| bool ResponseCalibration::WriteCalibrationV3(unsigned int chipIndex) |
| { |
| if (!fOffset) |
| return false; |
| int ii, j, k; |
| char str[1000]; |
| char strt[1000]; |
| short tempShort; |
| CalibrationData *data = fCalibrationData[chipIndex]; |
| CalibrationData::CalibrationDataChannel * chn; |
| // Open File |
| fBoard->GetCalibrationDirectory(strt); |
| sprintf(str, "%s/board%d", strt, fBoard->GetBoardSerialNumber()); |
| if (MakeDir(str) == -1) { |
| printf("Error: Cannot create directory \"%s\"\n", str); |
| return false; |
| } |
| sprintf(str, "%s/board%d/ResponseCalib_board%d_chip%d_%dMHz.bin", strt, fBoard->GetBoardSerialNumber(), |
| fBoard->GetBoardSerialNumber(), chipIndex, static_cast < int >(fBoard->GetNominalFrequency() * 1000)); |
| fCalibFile = fopen(str, "wb"); |
| if (fCalibFile == NULL) { |
| printf("Error: Cannot write to file \"%s\"\n", str); |
| return false; |
| } |
| // Write File |
| fwrite(&data->fNumberOfGridPoints, 1, 1, fCalibFile); |
| tempShort = static_cast < short >(data->fStartTemperature) * 10; |
| fwrite(&tempShort, 2, 1, fCalibFile); |
| tempShort = static_cast < short >(data->fEndTemperature) * 10; |
| fwrite(&tempShort, 2, 1, fCalibFile); |
| fwrite(&data->fMin, 4, 1, fCalibFile); |
| fwrite(&data->fMax, 4, 1, fCalibFile); |
| fwrite(&data->fNumberOfLimitGroups, 1, 1, fCalibFile); |
| for (ii = 0; ii < kNumberOfCalibChannelsV3; ii++) { |
| chn = data->fChannel[ii]; |
| for (j = 0; j < kNumberOfBins; j++) { |
| fwrite(&chn->fLimitGroup[j], 1, 1, fCalibFile); |
| fwrite(&chn->fLookUpOffset[j], 2, 1, fCalibFile); |
| fwrite(&chn->fNumberOfLookUpPoints[j], 1, 1, fCalibFile); |
| for (k = 0; k < chn->fNumberOfLookUpPoints[j]; k++) { |
| fwrite(&chn->fLookUp[j][k], 1, 1, fCalibFile); |
| } |
| for (k = 0; k < data->fNumberOfGridPoints; k++) { |
| fwrite(&chn->fData[j][k], 2, 1, fCalibFile); |
| } |
| fwrite(&chn->fOffsetADC[j], 2, 1, fCalibFile); |
| fwrite(&chn->fOffset[j], 2, 1, fCalibFile); |
| } |
| } |
| fclose(fCalibFile); |
| printf("Calibration successfully written to\n\"%s\"\n", str); |
| return true; |
| } |
| /*------------------------------------------------------------------*/ |
| bool ResponseCalibration::WriteCalibrationV4(unsigned int chipIndex) |
| { |
| if (!fOffset) |
| return false; |
| int ii, j; |
| char str[1000]; |
| char strt[1000]; |
| CalibrationData *data = fCalibrationData[chipIndex]; |
| CalibrationData::CalibrationDataChannel * chn; |
| // Open File |
| fBoard->GetCalibrationDirectory(strt); |
| sprintf(str, "%s/board%d", strt, fBoard->GetBoardSerialNumber()); |
| if (MakeDir(str) == -1) { |
| printf("Error: Cannot create directory \"%s\"\n", str); |
| return false; |
| } |
| sprintf(str, "%s/board%d/ResponseCalib_board%d_chip%d_%dMHz.bin", strt, fBoard->GetBoardSerialNumber(), |
| fBoard->GetBoardSerialNumber(), chipIndex, static_cast < int >(fBoard->GetNominalFrequency() * 1000)); |
| fCalibFile = fopen(str, "wb"); |
| if (fCalibFile == NULL) { |
| printf("Error: Cannot write to file \"%s\"\n", str); |
| return false; |
| } |
| // Write File |
| for (ii = 0; ii < kNumberOfCalibChannelsV4; ii++) { |
| chn = data->fChannel[ii]; |
| for (j = 0; j < kNumberOfBins; j++) { |
| fwrite(&chn->fOffset[j], 2, 1, fCalibFile); |
| fwrite(&chn->fGain[j], 2, 1, fCalibFile); |
| } |
| } |
| fclose(fCalibFile); |
| printf("Calibration successfully written to\n\"%s\"\n", str); |
| return true; |
| } |
| /*------------------------------------------------------------------*/ |
| void ResponseCalibration::CalibrationTrigger(int mode, double voltage) |
| { |
| fBoard->Reinit(); |
| fBoard->EnableAcal(mode, voltage); |
| fBoard->StartDomino(); |
| fBoard->SoftTrigger(); |
| while (fBoard->IsBusy()) { |
| } |
| } |
| /*------------------------------------------------------------------*/ |
| void ResponseCalibration::CalibrationStart(double voltage) |
| { |
| fBoard->SetDominoMode(1); |
| fBoard->EnableAcal(0, voltage); |
| fBoard->StartDomino(); |
| fBoard->IsBusy(); |
| fBoard->IsBusy(); |
| fBoard->IsBusy(); |
| } |
| /*------------------------------------------------------------------*/ |
| bool ResponseCalibration::RecordCalibrationPoints(int chipNumber) |
| { |
| if (!fInitialized) |
| return true; |
| if (fBoard->GetDRSType() == 3) |
| return RecordCalibrationPointsV4(chipNumber); |
| else |
| return RecordCalibrationPointsV3(chipNumber); |
| } |
| /*------------------------------------------------------------------*/ |
| bool ResponseCalibration::RecordCalibrationPointsV3(int chipNumber) |
| { |
| int j, k, ii; |
| int notdone, nsample; |
| double voltage; |
| float mean; |
| const double minVolt = 0.006; |
| const double xpos[50] = |
| { 0.010, 0.027, 0.052, 0.074, 0.096, 0.117, 0.136, 0.155, 0.173, 0.191, 0.208, 0.226, 0.243, 0.260, |
| 0.277, 0.294, 0.310, |
| 0.325, 0.342, 0.358, 0.374, 0.390, 0.406, 0.422, 0.439, 0.457, 0.477, 0.497, 0.520, 0.546, 0.577, 0.611, |
| 0.656, 0.710, |
| 0.772, 0.842, 0.916, |
| 0.995, 1.075, 1.157, 1.240, 1.323, 1.407, 1.490, 1.575, 1.659, 1.744, 1.829, 1.914, 2.000 |
| }; |
| // Initialisations |
| if (fCurrentLowVoltPoint == 0) { |
| fBoard->SetDAC(fBoard->fDAC_CLKOFS, 0); |
| // Record Temperature |
| fCalibrationData[chipNumber]->fStartTemperature = static_cast < float >(fBoard->GetTemperature()); |
| } |
| // Record current Voltage |
| if (fCurrentLowVoltPoint < fNumberOfPointsLowVolt) |
| voltage = |
| (xpos[0] - minVolt) * fCurrentLowVoltPoint / static_cast < |
| double >(fNumberOfPointsLowVolt) + minVolt; |
| else |
| voltage = xpos[fCurrentPoint]; |
| fBoard->SetCalibVoltage(voltage); |
| fResponseY[fCurrentPoint + fCurrentLowVoltPoint] = static_cast < float >(voltage) * 1000; |
| // Loop Over Number Of Samples For Statistics |
| for (j = 0; j < fNumberOfSamples; j++) { |
| // Read Out Second Part of the Waveform |
| CalibrationTrigger(3, voltage); |
| fBoard->TransferWaves(); |
| for (ii = 0; ii < kNumberOfCalibChannelsV3; ii++) { |
| fBoard->GetRawWave(chipNumber, ii, fWaveFormMode3[ii][j]); |
| } |
| // Read Out First Part of the Waveform |
| CalibrationStart(voltage); |
| CalibrationTrigger(2, voltage); |
| fBoard->TransferWaves(); |
| for (ii = 0; ii < kNumberOfCalibChannelsV3; ii++) { |
| fBoard->GetRawWave(chipNumber, ii, fWaveFormMode2[ii][j]); |
| } |
| CalibrationStart(voltage); |
| } |
| // Average Sample Points |
| for (ii = 0; ii < kNumberOfCalibChannelsV3; ii++) { |
| for (k = 0; k < kNumberOfBins; k++) { |
| fResponseX[ii][k][fCurrentPoint + fCurrentLowVoltPoint] = 0; |
| for (j = 0; j < fNumberOfSamples; j++) { |
| fSampleUsed[j] = 1; |
| if (k < fNumberOfMode2Bins) |
| fSamples[j] = fWaveFormMode2[ii][j][k]; |
| else |
| fSamples[j] = fWaveFormMode3[ii][j][k]; |
| fResponseX[ii][k][fCurrentPoint + fCurrentLowVoltPoint] += fSamples[j]; |
| } |
| mean = fResponseX[ii][k][fCurrentPoint + fCurrentLowVoltPoint] / fNumberOfSamples; |
| notdone = 1; |
| nsample = fNumberOfSamples; |
| while (notdone) { |
| notdone = 0; |
| for (j = 0; j < fNumberOfSamples; j++) { |
| if (fSampleUsed[j] && abs(static_cast < int >(fSamples[j] - mean)) > 3) { |
| notdone = 1; |
| fSampleUsed[j] = 0; |
| nsample--; |
| fResponseX[ii][k][fCurrentPoint + fCurrentLowVoltPoint] -= fSamples[j]; |
| mean = fResponseX[ii][k][fCurrentPoint + fCurrentLowVoltPoint] / nsample; |
| } |
| } |
| } |
| fResponseX[ii][k][fCurrentPoint + fCurrentLowVoltPoint] = mean; |
| } |
| } |
| if (fCurrentLowVoltPoint < fNumberOfPointsLowVolt) |
| fCurrentLowVoltPoint++; |
| else |
| fCurrentPoint++; |
| if (fCurrentPoint == fNumberOfPoints) { |
| fCalibrationData[chipNumber]->fEndTemperature = static_cast < float >(fBoard->GetTemperature()); |
| fRecorded = true; |
| fFitted = false; |
| fOffset = false; |
| fCalibrationData[chipNumber]->fRead = false; |
| fCalibrationData[chipNumber]->fHasOffsetCalibration = false; |
| fBoard->SetCalibVoltage(0.0); |
| fBoard->EnableAcal(1, 0.0); |
| fBoard->SetDAC(fBoard->fDAC_CLKOFS, 0.0); |
| return true; |
| } |
| return false; |
| } |
| /*------------------------------------------------------------------*/ |
| bool ResponseCalibration::RecordCalibrationPointsV4(int chipNumber) |
| { |
| int i, j, k, n; |
| double voltage, s, s2, average; |
| if (fCurrentPoint == 0) { |
| fBoard->SetDominoMode(1); |
| fBoard->EnableAcal(1, 0); |
| fBoard->SoftTrigger(); |
| while (fBoard->IsBusy()); |
| fBoard->StartDomino(); |
| fCalibrationData[chipNumber]->fStartTemperature = static_cast < float >(fBoard->GetTemperature()); |
| } |
| voltage = 1.0 * fCurrentPoint / (static_cast < double >(fNumberOfPoints) - 1) +0.1; |
| fBoard->SetCalibVoltage(voltage); |
| Sleep(10); |
| fBoard->SetCalibVoltage(voltage); |
| Sleep(10); |
| // One dummy cycle for unknown reasons |
| fBoard->SoftTrigger(); |
| while (fBoard->IsBusy()); |
| fBoard->StartDomino(); |
| Sleep(50); |
| fBoard->TransferWaves(); |
| // Loop over number of samples for statistics |
| for (i = 0; i < fNumberOfSamples; i++) { |
| if (fBoard->Debug()) { |
| printf("%02d:%02d\r", fNumberOfPoints - fCurrentPoint, fNumberOfSamples - i); |
| fflush(stdout); |
| } |
| fBoard->SoftTrigger(); |
| while (fBoard->IsBusy()); |
| fBoard->StartDomino(); |
| Sleep(50); |
| fBoard->TransferWaves(); |
| for (j = 0; j < kNumberOfCalibChannelsV4; j++) { |
| fBoard->GetRawWave(chipNumber, j, fWaveFormMode3[j][i]); |
| } |
| } |
| // Calculate averages |
| for (i = 0; i < kNumberOfCalibChannelsV4; i++) { |
| for (k = 0; k < kNumberOfBins; k++) { |
| s = s2 = 0; |
| for (j = 0; j < fNumberOfSamples; j++) { |
| s += fWaveFormMode3[i][j][k]; |
| s2 += fWaveFormMode3[i][j][k] * fWaveFormMode3[i][j][k]; |
| } |
| n = fNumberOfSamples; |
| average = s / n; |
| fResponseX[i][k][fCurrentPoint] = static_cast < float >(average); |
| } |
| } |
| fCurrentPoint++; |
| if (fCurrentPoint == fNumberOfPoints) { |
| fCalibrationData[chipNumber]->fEndTemperature = static_cast < float >(fBoard->GetTemperature()); |
| fRecorded = true; |
| return true; |
| } |
| return false; |
| } |
| /*------------------------------------------------------------------*/ |
| bool ResponseCalibration::FitCalibrationPoints(int chipNumber) |
| { |
| if (!fRecorded || fFitted) |
| return true; |
| if (fBoard->GetDRSType() == 3) |
| return FitCalibrationPointsV4(chipNumber); |
| else |
| return FitCalibrationPointsV3(chipNumber); |
| } |
| /*------------------------------------------------------------------*/ |
| bool ResponseCalibration::FitCalibrationPointsV3(int chipNumber) |
| { |
| int i, j, k; |
| float x1, x2, y1, y2; |
| float uu; |
| float yc, yr; |
| float xminExt, xrangeExt; |
| float xmin, xrange; |
| float average, averageError, averageExt, averageErrorExt; |
| unsigned short i0, i1; |
| CalibrationData *data = fCalibrationData[chipNumber]; |
| CalibrationData::CalibrationDataChannel * chn = data->fChannel[fCurrentFitChannel]; |
| data->DeletePreCalculatedBSpline(); |
| if (fCurrentFitBin == 0 && fCurrentFitChannel == 0) { |
| data->fNumberOfLimitGroups = 0; |
| data->fMin = 100000; |
| data->fMax = -100000; |
| for (i = 0; i < kNumberOfCalibChannelsV3; i++) { |
| for (j = 0; j < kNumberOfBins; j++) { |
| if (data->fMin > fResponseX[i][j][fNumberOfPointsLowVolt + fNumberOfPoints - 1]) |
| data->fMin = fResponseX[i][j][fNumberOfPointsLowVolt + fNumberOfPoints - 1]; |
| if (data->fMax < fResponseX[i][j][fNumberOfPointsLowVolt]) |
| data->fMax = fResponseX[i][j][fNumberOfPointsLowVolt]; |
| } |
| } |
| } |
| // Low Volt |
| i0 = static_cast < unsigned short >(fResponseX[fCurrentFitChannel][fCurrentFitBin][0]); |
| i1 = static_cast < |
| unsigned short >(fResponseX[fCurrentFitChannel][fCurrentFitBin][fNumberOfPointsLowVolt]) + 1; |
| chn->fLookUpOffset[fCurrentFitBin] = i0; |
| delete chn->fLookUp[fCurrentFitBin]; |
| if (i0 - i1 + 1 < 2) { |
| chn->fNumberOfLookUpPoints[fCurrentFitBin] = 2; |
| chn->fLookUp[fCurrentFitBin] = new unsigned char[2]; |
| chn->fLookUp[fCurrentFitBin][0] = 0; |
| chn->fLookUp[fCurrentFitBin][1] = 0; |
| } else { |
| chn->fNumberOfLookUpPoints[fCurrentFitBin] = i0 - i1 + 1; |
| chn->fLookUp[fCurrentFitBin] = new unsigned char[i0 - i1 + 1]; |
| for (i = 0; i < i0 - i1 + 1; i++) { |
| for (j = 0; j < fNumberOfPointsLowVolt; j++) { |
| if (i0 - i >= fResponseX[fCurrentFitChannel][fCurrentFitBin][j + 1]) { |
| x1 = fResponseX[fCurrentFitChannel][fCurrentFitBin][j]; |
| x2 = fResponseX[fCurrentFitChannel][fCurrentFitBin][j + 1]; |
| y1 = fResponseY[j]; |
| y2 = fResponseY[j + 1]; |
| chn->fLookUp[fCurrentFitBin][i] = |
| static_cast < unsigned char >(((y2 - y1) * (i0 - i - x1) / (x2 - x1) + y1) / fPrecision); |
| break; |
| } |
| } |
| } |
| } |
| // Copy Points |
| for (i = 0; i < fNumberOfPoints; i++) { |
| fPntX[0][i] = fResponseX[fCurrentFitChannel][fCurrentFitBin][fNumberOfPointsLowVolt + i]; |
| fPntY[0][i] = fResponseY[fNumberOfPointsLowVolt + i]; |
| } |
| // Fit BSpline |
| for (i = 0; i < fNumberOfPoints; i++) { |
| fUValues[0][i] = static_cast < float >(1 - i / (fNumberOfPoints - 1.)); |
| } |
| if (!Approx(fPntX[0], fUValues[0], fNumberOfPoints, fNumberOfGridPoints, fResX[fCurrentFitBin])) |
| return true; |
| if (!Approx(fPntY[0], fUValues[0], fNumberOfPoints, fNumberOfGridPoints, fRes[fCurrentFitBin])) |
| return true; |
| // X constant fit |
| for (k = 0; k < fNumberOfXConstPoints - 2; k++) { |
| fPntX[1][k + 1] = |
| GetValue(fResX[fCurrentFitBin], |
| static_cast < float >(1 - k / static_cast < float >(fNumberOfXConstPoints - 3)), |
| fNumberOfGridPoints); |
| fPntY[1][k + 1] = |
| GetValue(fRes[fCurrentFitBin], |
| static_cast < float >(1 - k / static_cast < float >(fNumberOfXConstPoints - 3)), |
| fNumberOfGridPoints); |
| } |
| xmin = fPntX[1][fNumberOfXConstPoints - 2]; |
| xrange = fPntX[1][1] - xmin; |
| for (i = 0; i < fNumberOfXConstPoints - 2; i++) { |
| fUValues[1][i + 1] = (fPntX[1][i + 1] - xmin) / xrange; |
| } |
| if (!Approx |
| (&fPntY[1][1], &fUValues[1][1], fNumberOfXConstPoints - 2, fNumberOfXConstGridPoints, chn->fTempData)) |
| return true; |
| // error statistics |
| if (fShowStatistics) { |
| for (i = 0; i < fNumberOfPoints; i++) { |
| uu = (fPntX[0][i] - xmin) / xrange; |
| yc = GetValue(chn->fTempData, uu, fNumberOfXConstGridPoints); |
| yr = fPntY[0][i]; |
| fStatisticsApprox[i][fCurrentFitBin + fCurrentFitChannel * kNumberOfBins] = yc - yr; |
| } |
| } |
| // Add min and max point |
| chn->fLimitGroup[fCurrentFitBin] = 0; |
| while (xmin - kBSplineXMinOffset > data->fMin + kBSplineXMinOffset * chn->fLimitGroup[fCurrentFitBin]) { |
| chn->fLimitGroup[fCurrentFitBin]++; |
| } |
| if (data->fNumberOfLimitGroups <= chn->fLimitGroup[fCurrentFitBin]) |
| data->fNumberOfLimitGroups = chn->fLimitGroup[fCurrentFitBin] + 1; |
| xminExt = data->fMin + kBSplineXMinOffset * chn->fLimitGroup[fCurrentFitBin]; |
| xrangeExt = data->fMax - xminExt; |
| fPntX[1][0] = data->fMax; |
| uu = (fPntX[1][0] - xmin) / xrange; |
| fPntY[1][0] = GetValue(chn->fTempData, uu, fNumberOfXConstGridPoints); |
| fPntX[1][fNumberOfXConstPoints - 1] = xminExt; |
| uu = (fPntX[1][fNumberOfXConstPoints - 1] - xmin) / xrange; |
| fPntY[1][fNumberOfXConstPoints - 1] = GetValue(chn->fTempData, uu, fNumberOfXConstGridPoints); |
| for (i = 0; i < fNumberOfXConstPoints; i++) { |
| fUValues[1][i] = (fPntX[1][i] - xminExt) / xrangeExt; |
| } |
| if (!Approx(fPntY[1], fUValues[1], fNumberOfXConstPoints, fNumberOfXConstGridPoints, chn->fTempData)) |
| return true; |
| // error statistics |
| if (fShowStatistics) { |
| for (i = 0; i < fNumberOfPoints; i++) { |
| uu = (fPntX[0][i] - xminExt) / xrangeExt; |
| yc = GetValue(chn->fTempData, uu, fNumberOfXConstGridPoints); |
| yr = fPntY[0][i]; |
| fStatisticsApproxExt[i][fCurrentFitBin + fCurrentFitChannel * kNumberOfBins] = yc - yr; |
| } |
| } |
| for (i = 0; i < fNumberOfXConstGridPoints; i++) { |
| chn->fData[fCurrentFitBin][i] = static_cast < short >(chn->fTempData[i] / fPrecision); |
| } |
| // write end of file |
| fCurrentFitBin++; |
| if (fCurrentFitBin == kNumberOfBins) { |
| fCurrentFitChannel++; |
| fCurrentFitBin = 0; |
| } |
| if (fCurrentFitChannel == kNumberOfCalibChannelsV3) { |
| if (fShowStatistics) { |
| for (i = 0; i < fNumberOfPoints; i++) { |
| average = 0; |
| averageError = 0; |
| averageExt = 0; |
| averageErrorExt = 0; |
| for (j = 0; j < kNumberOfCalibChannelsV3 * kNumberOfBins; j++) { |
| average += fStatisticsApprox[i][j]; |
| averageError += fStatisticsApprox[i][j] * fStatisticsApprox[i][j]; |
| averageExt += fStatisticsApproxExt[i][j]; |
| averageErrorExt += fStatisticsApproxExt[i][j] * fStatisticsApproxExt[i][j]; |
| } |
| average /= kNumberOfCalibChannelsV3 * kNumberOfBins; |
| averageError = |
| sqrt((averageError - |
| average * average / kNumberOfCalibChannelsV3 * kNumberOfBins) / |
| (kNumberOfCalibChannelsV3 * kNumberOfBins - 1)); |
| averageExt /= kNumberOfCalibChannelsV3 * kNumberOfBins; |
| averageErrorExt = |
| sqrt((averageErrorExt - |
| averageExt * averageExt / kNumberOfCalibChannelsV3 * kNumberOfBins) / |
| (kNumberOfCalibChannelsV3 * kNumberOfBins - 1)); |
| printf("Error at %3.1f V : % 2.3f +- % 2.3f ; % 2.3f +- % 2.3f\n", fPntY[0][i], average, |
| averageError, averageExt, averageErrorExt); |
| } |
| } |
| fFitted = true; |
| fOffset = false; |
| fCalibrationData[chipNumber]->fRead = true; |
| fCalibrationData[chipNumber]->fHasOffsetCalibration = false; |
| data->PreCalculateBSpline(); |
| return true; |
| } |
| return false; |
| } |
| /*------------------------------------------------------------------*/ |
| bool ResponseCalibration::FitCalibrationPointsV4(int chipNumber) |
| { |
| if (!fRecorded || fFitted) |
| return true; |
| int i; |
| double par[2]; |
| static int error; |
| CalibrationData *data = fCalibrationData[chipNumber]; |
| CalibrationData::CalibrationDataChannel * chn = data->fChannel[fCurrentFitChannel]; |
| if (fCurrentFitBin == 0 && fCurrentFitChannel == 0) { |
| error = 0; |
| for (i = 0; i < fNumberOfPoints; i++) |
| fWWFit[i] = 1; |
| } |
| for (i = 0; i < fNumberOfPoints; i++) { |
| fXXFit[i] = 1.0 * i / (static_cast < double >(fNumberOfPoints) - 1) +0.1; |
| fYYFit[i] = fResponseX[fCurrentFitChannel][fCurrentFitBin][i]; |
| if (fCurrentFitBin == 10 && fCurrentFitChannel == 1) { |
| fXXSave[i] = fXXFit[i]; |
| fYYSave[i] = fYYFit[i]; |
| } |
| } |
| // DRSBoard::LinearRegression(fXXFit, fYYFit, fNumberOfPoints, &par[1], &par[0]); |
| // exclude first two points (sometimes are on limit of FADC) |
| DRSBoard::LinearRegression(fXXFit + 2, fYYFit + 2, fNumberOfPoints - 2, &par[1], &par[0]); |
| chn->fOffset[fCurrentFitBin] = static_cast < unsigned short >(par[0] + 0.5); |
| chn->fGain[fCurrentFitBin] = static_cast < unsigned short >(par[1] + 0.5); |
| // Remember min/max of gain |
| if (fCurrentFitBin == 0 && fCurrentFitChannel == 0) |
| fGainMin = fGainMax = chn->fGain[0]; |
| if (chn->fGain[fCurrentFitBin] < fGainMin) |
| fGainMin = chn->fGain[fCurrentFitBin]; |
| if (chn->fGain[fCurrentFitBin] > fGainMax) |
| fGainMax = chn->fGain[fCurrentFitBin]; |
| // abort if outside normal region |
| if (chn->fGain[fCurrentFitBin] / 4096.0 < 0.8 || chn->fGain[fCurrentFitBin] / 4096.0 > 1) { |
| error++; |
| if (error < 20) |
| printf("Gain=%1.3lf for bin %d on channel %d on chip %d outside valid region\n", |
| chn->fGain[fCurrentFitBin] / 4096.0, fCurrentFitBin, fCurrentFitChannel, chipNumber); |
| } |
| if (fCurrentFitChannel == 1 && fCurrentFitBin == 10) { |
| for (i = 0; i < fNumberOfPoints; i++) { |
| fXXSave[i] = fXXFit[i]; |
| fYYSave[i] = (fYYFit[i] - chn->fOffset[10]) / chn->fGain[10] - fXXFit[i]; |
| } |
| } |
| fCurrentFitBin++; |
| if (fCurrentFitBin == kNumberOfBins) { |
| fCurrentFitChannel++; |
| fCurrentFitBin = 0; |
| } |
| if (fCurrentFitChannel == kNumberOfCalibChannelsV4) { |
| if (fBoard->Debug()) { |
| printf("Gain min=%1.3lf max=%1.3lf\n", fGainMin / 4096.0, fGainMax / 4096.0); |
| fflush(stdout); |
| } |
| // allow up to three bad bins |
| if (error > 3) { |
| printf("Aborting calibration!\n"); |
| return true; |
| } |
| fFitted = true; |
| fOffset = false; |
| fCalibrationData[chipNumber]->fRead = true; |
| fCalibrationData[chipNumber]->fHasOffsetCalibration = false; |
| return true; |
| } |
| return false; |
| } |
| unsigned int millitime() |
| { |
| #ifdef _MSC_VER |
| return (int) GetTickCount(); |
| #else |
| struct timeval tv; |
| gettimeofday(&tv, NULL); |
| return tv.tv_sec * 1000 + tv.tv_usec / 1000; |
| #endif |
| return 0; |
| } |
| /*------------------------------------------------------------------*/ |
| bool ResponseCalibration::OffsetCalibration(int chipNumber) |
| { |
| if (!fFitted || fOffset) |
| return true; |
| if (fBoard->GetDRSType() == 3) |
| return OffsetCalibrationV4(chipNumber); |
| else |
| return OffsetCalibrationV3(chipNumber); |
| } |
| /*------------------------------------------------------------------*/ |
| bool ResponseCalibration::OffsetCalibrationV3(int chipNumber) |
| { |
| int k, ii, j; |
| int t1, t2; |
| float mean, error; |
| CalibrationData *data = fCalibrationData[chipNumber]; |
| CalibrationData::CalibrationDataChannel * chn; |
| if (fCurrentSample == 0) { |
| data->fHasOffsetCalibration = false; |
| fBoard->SetCalibVoltage(0.0); |
| fBoard->EnableAcal(0, 0.0); |
| } |
| // Loop Over Number Of Samples For Statistics |
| t1 = millitime(); |
| fBoard->SoftTrigger(); |
| while (fBoard->IsBusy()) { |
| } |
| fBoard->TransferWaves(); |
| for (ii = 0; ii < kNumberOfCalibChannelsV3; ii++) { |
| fBoard->GetRawWave(chipNumber, ii, fWaveFormOffsetADC[ii][fCurrentSample]); |
| fBoard->CalibrateWaveform(chipNumber, ii, fWaveFormOffsetADC[ii][fCurrentSample], |
| fWaveFormOffset[ii][fCurrentSample], true, false, false, 0, true); |
| } |
| fBoard->StartDomino(); |
| fBoard->IsBusy(); |
| fBoard->IsBusy(); |
| fBoard->IsBusy(); |
| t2 = millitime(); |
| while (t2 - t1 < (1000 / fTriggerFrequency)) { |
| t2 = millitime(); |
| } |
| fCurrentSample++; |
| if (fCurrentSample == fNumberOfSamples) { |
| // Average Sample Points |
| float *sample = new float[fNumberOfSamples]; |
| for (ii = 0; ii < kNumberOfCalibChannelsV3; ii++) { |
| chn = data->fChannel[ii]; |
| for (k = 0; k < kNumberOfBins; k++) { |
| for (j = 0; j < fNumberOfSamples; j++) |
| sample[j] = static_cast < float >(fWaveFormOffset[ii][j][k]); |
| Average(1, sample, fNumberOfSamples, mean, error, 2); |
| chn->fOffset[k] = static_cast < short >(mean); |
| for (j = 0; j < fNumberOfSamples; j++) |
| sample[j] = fWaveFormOffsetADC[ii][j][k]; |
| Average(1, sample, fNumberOfSamples, mean, error, 2); |
| chn->fOffsetADC[k] = static_cast < unsigned short >(mean); |
| } |
| } |
| fOffset = true; |
| fCalibrationData[chipNumber]->fHasOffsetCalibration = true; |
| delete[] sample; |
| return true; |
| } |
| return false; |
| } |
| /*------------------------------------------------------------------*/ |
| bool ResponseCalibration::OffsetCalibrationV4(int chipNumber) |
| { |
| int k, ii, j; |
| float mean, error; |
| CalibrationData *data = fCalibrationData[chipNumber]; |
| CalibrationData::CalibrationDataChannel * chn; |
| /* switch DRS to input, hope that no real signal occurs */ |
| if (fCurrentSample == 0) { |
| data->fHasOffsetCalibration = false; |
| fBoard->SetCalibVoltage(0.0); |
| fBoard->EnableAcal(0, 0.0); |
| /* one dummy trigger for unknown reasons */ |
| fBoard->SoftTrigger(); |
| while (fBoard->IsBusy()); |
| fBoard->StartDomino(); |
| Sleep(50); |
| } |
| // Loop Over Number Of Samples For Statistics |
| fBoard->SoftTrigger(); |
| while (fBoard->IsBusy()); |
| fBoard->TransferWaves(); |
| for (ii = 0; ii < kNumberOfCalibChannelsV4; ii++) |
| fBoard->GetRawWave(chipNumber, ii, fWaveFormOffsetADC[ii][fCurrentSample]); |
| fBoard->StartDomino(); |
| Sleep(50); |
| fCurrentSample++; |
| if (fBoard->Debug()) { |
| printf("%02d\r", fNumberOfSamples - fCurrentSample); |
| fflush(stdout); |
| } |
| if (fCurrentSample == fNumberOfSamples) { |
| // Average Sample Points |
| float *sample = new float[fNumberOfSamples]; |
| for (ii = 0; ii < kNumberOfCalibChannelsV3; ii++) { |
| chn = data->fChannel[ii]; |
| for (k = 0; k < kNumberOfBins; k++) { |
| for (j = 0; j < fNumberOfSamples; j++) |
| sample[j] = static_cast < float >(fWaveFormOffsetADC[ii][j][k]); |
| Average(1, sample, fNumberOfSamples, mean, error, 2); |
| chn->fOffset[k] = static_cast < unsigned short >(mean); |
| } |
| } |
| fOffset = true; |
| fCalibrationData[chipNumber]->fHasOffsetCalibration = true; |
| delete[] sample; |
| return true; |
| } |
| return false; |
| } |
| /*------------------------------------------------------------------*/ |
| void ResponseCalibration::InitFields(int numberOfPointsLowVolt, int numberOfPoints, int numberOfMode2Bins, |
| int numberOfSamples, int numberOfGridPoints, int numberOfXConstPoints, |
| int numberOfXConstGridPoints, double triggerFrequency, |
| int showStatistics) |
| { |
| int ii, j, i; |
| fInitialized = true; |
| fNumberOfPointsLowVolt = numberOfPointsLowVolt; |
| fNumberOfPoints = numberOfPoints; |
| fNumberOfMode2Bins = numberOfMode2Bins; |
| fNumberOfSamples = numberOfSamples; |
| fNumberOfGridPoints = numberOfGridPoints; |
| fNumberOfXConstPoints = numberOfXConstPoints; |
| fNumberOfXConstGridPoints = numberOfXConstGridPoints; |
| fTriggerFrequency = triggerFrequency; |
| fShowStatistics = showStatistics; |
| fCurrentPoint = 0; |
| fCurrentSample = 0; |
| fCurrentFitChannel = 0; |
| fCurrentFitBin = 0; |
| for (ii = 0; ii < kNumberOfCalibChannelsV3; ii++) { |
| for (j = 0; j < kNumberOfBins; j++) { |
| fResponseX[ii][j] = new float[fNumberOfPoints + fNumberOfPointsLowVolt]; |
| } |
| } |
| fResponseY = new float[fNumberOfPoints + fNumberOfPointsLowVolt]; |
| for (ii = 0; ii < kNumberOfCalibChannelsV3; ii++) { |
| fWaveFormMode3[ii] = new unsigned short *[fNumberOfSamples]; |
| fWaveFormMode2[ii] = new unsigned short *[fNumberOfSamples]; |
| fWaveFormOffset[ii] = new short *[fNumberOfSamples]; |
| fWaveFormOffsetADC[ii] = new unsigned short *[fNumberOfSamples]; |
| for (i = 0; i < fNumberOfSamples; i++) { |
| fWaveFormMode3[ii][i] = new unsigned short[kNumberOfBins]; |
| fWaveFormMode2[ii][i] = new unsigned short[kNumberOfBins]; |
| fWaveFormOffset[ii][i] = new short[kNumberOfBins]; |
| fWaveFormOffsetADC[ii][i] = new unsigned short[kNumberOfBins]; |
| } |
| } |
| fSamples = new unsigned short[fNumberOfSamples]; |
| fSampleUsed = new int[fNumberOfSamples]; |
| for (j = 0; j < kNumberOfBins; j++) { |
| fRes[j] = new float[fNumberOfGridPoints]; |
| fResX[j] = new float[fNumberOfGridPoints]; |
| } |
| for (i = 0; i < 2; i++) { |
| fPntX[i] = new float[fNumberOfPoints * (1 - i) + fNumberOfXConstPoints * i]; |
| fPntY[i] = new float[fNumberOfPoints * (1 - i) + fNumberOfXConstPoints * i]; |
| fUValues[i] = new float[fNumberOfPoints * (1 - i) + fNumberOfXConstPoints * i]; |
| } |
| fXXFit = new double[fNumberOfPoints]; |
| fYYFit = new double[fNumberOfPoints]; |
| fWWFit = new double[fNumberOfPoints]; |
| fYYFitRes = new double[fNumberOfPoints]; |
| fYYSave = new double[fNumberOfPoints]; |
| fXXSave = new double[fNumberOfPoints]; |
| fStatisticsApprox = new float *[fNumberOfPoints]; |
| fStatisticsApproxExt = new float *[fNumberOfPoints]; |
| for (i = 0; i < fNumberOfPoints; i++) { |
| fStatisticsApprox[i] = new float[kNumberOfCalibChannelsV3 * kNumberOfBins]; |
| fStatisticsApproxExt[i] = new float[kNumberOfCalibChannelsV3 * kNumberOfBins]; |
| } |
| for (i = 0; i < kNumberOfChipsMax; i++) { |
| fCalibrationData[i] = new CalibrationData(numberOfXConstGridPoints); |
| } |
| } |
| /*------------------------------------------------------------------*/ |
| void ResponseCalibration::DeleteFields() |
| { |
| if (!fInitialized) |
| return; |
| fInitialized = false; |
| int ii, j, i; |
| for (ii = 0; ii < kNumberOfCalibChannelsV3; ii++) { |
| for (j = 0; j < kNumberOfBins; j++) { |
| delete fResponseX[ii][j]; |
| } |
| } |
| delete fResponseY; |
| for (ii = 0; ii < kNumberOfCalibChannelsV3; ii++) { |
| for (i = 0; i < fNumberOfSamples; i++) { |
| if (fWaveFormMode3[ii] != NULL) |
| delete fWaveFormMode3[ii][i]; |
| if (fWaveFormMode2[ii] != NULL) |
| delete fWaveFormMode2[ii][i]; |
| if (fWaveFormOffset[ii] != NULL) |
| delete fWaveFormOffset[ii][i]; |
| if (fWaveFormOffsetADC[ii] != NULL) |
| delete fWaveFormOffsetADC[ii][i]; |
| } |
| delete fWaveFormMode3[ii]; |
| delete fWaveFormMode2[ii]; |
| delete fWaveFormOffset[ii]; |
| delete fWaveFormOffsetADC[ii]; |
| } |
| delete fSamples; |
| delete fSampleUsed; |
| for (j = 0; j < kNumberOfBins; j++) { |
| delete fRes[j]; |
| delete fResX[j]; |
| } |
| for (i = 0; i < 2; i++) { |
| delete fPntX[i]; |
| delete fPntY[i]; |
| delete fUValues[i]; |
| } |
| delete fXXFit; |
| delete fYYFit; |
| delete fWWFit; |
| delete fYYFitRes; |
| delete fYYSave; |
| delete fXXSave; |
| for (i = 0; i < fNumberOfPoints; i++) { |
| delete fStatisticsApprox[i]; |
| delete fStatisticsApproxExt[i]; |
| } |
| delete fStatisticsApprox; |
| delete fStatisticsApproxExt; |
| for (i = 0; i < kNumberOfChipsMax; i++) |
| delete fCalibrationData[i]; |
| } |
| /*------------------------------------------------------------------*/ |
| double ResponseCalibration::GetTemperature(unsigned int chipIndex) |
| { |
| if (fCalibrationData[chipIndex] == NULL) |
| return 0; |
| if (!fCalibrationData[chipIndex]->fRead) |
| return 0; |
| return (fCalibrationData[chipIndex]->fStartTemperature + fCalibrationData[chipIndex]->fEndTemperature) / 2; |
| } |
| /*------------------------------------------------------------------*/ |
| bool ResponseCalibration::Calibrate(unsigned int chipIndex, unsigned int channel, unsigned short *adcWaveform, |
| short *uWaveform, int triggerCell, float threshold, bool offsetCalib) |
| { |
| int i; |
| unsigned int NumberOfCalibChannels; |
| int hasOffset; |
| bool aboveThreshold; |
| float wave, v; |
| int j, irot; |
| CalibrationData *data = fCalibrationData[chipIndex]; |
| CalibrationData::CalibrationDataChannel * chn; |
| if (fBoard->GetDRSType() == 3) |
| NumberOfCalibChannels = kNumberOfCalibChannelsV4; |
| else |
| NumberOfCalibChannels = kNumberOfCalibChannelsV3; |
| if (channel >= NumberOfCalibChannels || data == NULL) { |
| for (i = 0; i < kNumberOfBins; i++) { |
| irot = i; |
| if (triggerCell > -1) |
| irot = (triggerCell + i) % kNumberOfBins; |
| uWaveform[i] = adcWaveform[irot]; |
| } |
| return true; |
| } |
| if (!data->fRead) { |
| for (i = 0; i < kNumberOfBins; i++) { |
| uWaveform[i] = adcWaveform[i]; |
| } |
| return true; |
| } |
| chn = data->fChannel[channel]; |
| hasOffset = data->fHasOffsetCalibration; |
| aboveThreshold = (threshold == 0); // if threshold equal zero, always return true |
| short offset; |
| // Calibrate |
| for (i = 0; i < kNumberOfBins; i++) { |
| if (fBoard->GetDRSType() != 3) { |
| irot = i; |
| if (triggerCell > -1) |
| irot = (triggerCell + i) % kNumberOfBins; |
| offset = offsetCalib ? chn->fOffset[irot] : 0; |
| if (adcWaveform[irot] > chn->fLookUpOffset[irot]) { |
| uWaveform[i] = |
| ((chn->fLookUp[irot][0] - chn->fLookUp[irot][1]) * (adcWaveform[irot] - |
| chn->fLookUpOffset[irot]) + |
| chn->fLookUp[irot][0]); |
| } else if (adcWaveform[irot] <= chn->fLookUpOffset[irot] |
| && adcWaveform[irot] > chn->fLookUpOffset[irot] - chn->fNumberOfLookUpPoints[irot]) { |
| uWaveform[i] = chn->fLookUp[irot][chn->fLookUpOffset[irot] - adcWaveform[irot]]; |
| } else { |
| wave = 0; |
| for (j = 0; j < kBSplineOrder; j++) { |
| wave += |
| chn->fData[irot][data->fBSplineOffsetLookUp[adcWaveform[irot]][chn->fLimitGroup[irot]] + j] |
| * data->fBSplineLookUp[adcWaveform[irot]][chn->fLimitGroup[irot]][j]; |
| } |
| uWaveform[i] = static_cast < short >(wave); |
| } |
| // Offset Calibration |
| if (hasOffset) |
| uWaveform[i] -= offset; |
| } else { |
| irot = i; |
| if (triggerCell > -1) |
| irot = (triggerCell + i) % kNumberOfBins; |
| #if 0 /* not enabled yet for DRS3 */ |
| offset = offsetCalib ? chn->fOffset[irot] : 0; |
| #else |
| offset = chn->fOffset[irot]; |
| #endif |
| v = static_cast < float >(adcWaveform[irot] - offset) / chn->fGain[irot]; |
| uWaveform[i] = static_cast < short >(v * 1000 / GetPrecision() + 0.5); |
| } |
| // Check for Threshold |
| if (!aboveThreshold) { |
| if (uWaveform[i] >= threshold) |
| aboveThreshold = true; |
| } |
| } |
| return aboveThreshold; |
| } |
| /*------------------------------------------------------------------*/ |
| bool ResponseCalibration::SubtractADCOffset(unsigned int chipIndex, unsigned int channel, |
| unsigned short *adcWaveform, |
| unsigned short *adcCalibratedWaveform, |
| unsigned short newBaseLevel) |
| { |
| int i; |
| unsigned int NumberOfCalibChannels; |
| CalibrationData *data = fCalibrationData[chipIndex]; |
| CalibrationData::CalibrationDataChannel * chn; |
| if (fBoard->GetDRSType() == 3) |
| NumberOfCalibChannels = kNumberOfCalibChannelsV4; |
| else |
| NumberOfCalibChannels = kNumberOfCalibChannelsV3; |
| if (channel >= NumberOfCalibChannels || data == NULL) |
| return false; |
| if (!data->fRead || !data->fHasOffsetCalibration) |
| return false; |
| chn = data->fChannel[channel]; |
| for (i = 0; i < kNumberOfBins; i++) |
| adcCalibratedWaveform[i] = adcWaveform[i] - chn->fOffsetADC[i] + newBaseLevel; |
| return true; |
| } |
| /*------------------------------------------------------------------*/ |
| bool ResponseCalibration::ReadCalibration(unsigned int chipIndex) |
| { |
| if (fBoard->GetDRSType() == 3) |
| return ReadCalibrationV4(chipIndex); |
| else |
| return ReadCalibrationV3(chipIndex); |
| } |
| /*------------------------------------------------------------------*/ |
| bool ResponseCalibration::ReadCalibrationV3(unsigned int chipIndex) |
| { |
| int k, l, m, num; |
| unsigned char ng; |
| short tempShort; |
| char fileName[2000]; |
| FILE *fileHandle; |
| char calibDir[1000]; |
| // Read Response Calibration |
| delete fCalibrationData[chipIndex]; |
| fCalibrationData[chipIndex] = NULL; |
| fBoard->GetCalibrationDirectory(calibDir); |
| sprintf(fileName, "%s/board%d/ResponseCalib_board%d_chip%d_%dMHz.bin", calibDir, |
| fBoard->GetBoardSerialNumber(), fBoard->GetBoardSerialNumber(), chipIndex, |
| static_cast < int >(fBoard->GetNominalFrequency() * 1000)); |
| fileHandle = fopen(fileName, "rb"); |
| if (fileHandle == NULL) { |
| printf("Board %d --> Could not find response calibration file:\n", fBoard->GetBoardSerialNumber()); |
| printf("%s\n", fileName); |
| return false; |
| } |
| // Number Of Grid Points |
| num = fread(&ng, 1, 1, fileHandle); |
| if (num != 1) { |
| printf("Error while reading response calibration file '%s'\n", fileName); |
| printf(" at 'NumberOfGridPoints'.\n"); |
| return false; |
| } |
| fCalibrationData[chipIndex] = new CalibrationData(ng); |
| CalibrationData *data = fCalibrationData[chipIndex]; |
| CalibrationData::CalibrationDataChannel * chn; |
| data->fRead = true; |
| data->fHasOffsetCalibration = 1; |
| data->DeletePreCalculatedBSpline(); |
| fCalibrationValid[chipIndex] = true; |
| // Start Temperature |
| num = fread(&tempShort, 2, 1, fileHandle); |
| if (num != 1) { |
| printf("Error while reading response calibration file '%s'\n", fileName); |
| printf(" at 'StartTemperature'.\n"); |
| return false; |
| } |
| data->fStartTemperature = static_cast < float >(tempShort) / 10; |
| // End Temperature |
| num = fread(&tempShort, 2, 1, fileHandle); |
| if (num != 1) { |
| printf("Error while reading response calibration file '%s'\n", fileName); |
| printf(" at 'EndTemperature'.\n"); |
| return false; |
| } |
| data->fEndTemperature = static_cast < float >(tempShort) / 10; |
| if (fBoard->GetDRSType() != 3) { |
| // Min |
| num = fread(&data->fMin, 4, 1, fileHandle); |
| if (num != 1) { |
| printf("Error while reading response calibration file '%s'\n", fileName); |
| printf(" at 'Min'.\n"); |
| return false; |
| } |
| // Max |
| num = fread(&data->fMax, 4, 1, fileHandle); |
| if (num != 1) { |
| printf("Error while reading response calibration file '%s'\n", fileName); |
| printf(" at 'Max'.\n"); |
| return false; |
| } |
| // Number Of Limit Groups |
| num = fread(&data->fNumberOfLimitGroups, 1, 1, fileHandle); |
| if (num != 1) { |
| printf("Error while reading response calibration file '%s'\n", fileName); |
| printf(" at 'NumberOfLimitGroups'.\n"); |
| return false; |
| } |
| } |
| // read channel |
| for (k = 0; k < kNumberOfCalibChannelsV3; k++) { |
| chn = data->fChannel[k]; |
| for (l = 0; l < kNumberOfBins; l++) { |
| if (fBoard->GetDRSType() != 3) { |
| // Range Group |
| num = fread(&chn->fLimitGroup[l], 1, 1, fileHandle); |
| if (num != 1) { |
| printf("Error while reading response calibration file '%s'\n", fileName); |
| printf(" at 'RangeGroup' of channel %d bin %d.\n", k, l); |
| return false; |
| } |
| // Look Up Offset |
| num = fread(&chn->fLookUpOffset[l], 2, 1, fileHandle); |
| if (num != 1) { |
| printf("Error while reading response calibration file '%s'\n", fileName); |
| printf(" at 'LookUpOffset' of channel %d bin %d.\n", k, l); |
| return false; |
| } |
| // Number Of Look Up Points |
| num = fread(&chn->fNumberOfLookUpPoints[l], 1, 1, fileHandle); |
| if (num != 1) { |
| printf("Error while reading response calibration file '%s'\n", fileName); |
| printf(" at 'NumberOfLookUpPoints' of channel %d bin %d.\n", k, l); |
| return false; |
| } |
| // Look Up Points |
| delete chn->fLookUp[l]; |
| chn->fLookUp[l] = new unsigned char[chn->fNumberOfLookUpPoints[l]]; |
| for (m = 0; m < chn->fNumberOfLookUpPoints[l]; m++) { |
| num = fread(&chn->fLookUp[l][m], 1, 1, fileHandle); |
| if (num != 1) { |
| printf("Error while reading response calibration file '%s'\n", fileName); |
| printf(" at 'LookUp %d' of channel %d bin %d.\n", m, k, l); |
| return false; |
| } |
| } |
| // Points |
| for (m = 0; m < data->fNumberOfGridPoints; m++) { |
| num = fread(&chn->fData[l][m], 2, 1, fileHandle); |
| if (num != 1) { |
| printf("Error while reading response calibration file '%s'\n", fileName); |
| printf(" at 'Point %d' of channel %d bin %d.\n", m, k, l); |
| return false; |
| } |
| } |
| // ADC Offset |
| num = fread(&chn->fOffsetADC[l], 2, 1, fileHandle); |
| if (num != 1) { |
| printf("Error while reading response calibration file '%s'\n", fileName); |
| printf(" at 'ADC Offset' of channel %d bin %d.\n", k, l); |
| return false; |
| } |
| } |
| // Offset |
| num = fread(&chn->fOffset[l], 2, 1, fileHandle); |
| if (num != 1) { |
| printf("Error while reading response calibration file '%s'\n", fileName); |
| printf(" at 'Offset' of channel %d bin %d.\n", k, l); |
| return false; |
| } |
| if (fBoard->GetDRSType() == 3) { |
| // Gain |
| num = fread(&chn->fGain[l], 2, 1, fileHandle); |
| if (num != 1) { |
| printf("Error while reading response calibration file '%s'\n", fileName); |
| printf(" at 'Gain' of channel %d bin %d.\n", k, l); |
| return false; |
| } |
| } |
| } |
| } |
| fclose(fileHandle); |
| if (fBoard->GetDRSType() != 3) { |
| data->PreCalculateBSpline(); |
| } |
| return true; |
| } |
| /*------------------------------------------------------------------*/ |
| bool ResponseCalibration::ReadCalibrationV4(unsigned int chipIndex) |
| { |
| int k, l, num; |
| char fileName[2000]; |
| FILE *fileHandle; |
| char calibDir[1000]; |
| // Read Response Calibration |
| fBoard->GetCalibrationDirectory(calibDir); |
| sprintf(fileName, "%s/board%d/ResponseCalib_board%d_chip%d_%dMHz.bin", calibDir, |
| fBoard->GetBoardSerialNumber(), fBoard->GetBoardSerialNumber(), chipIndex, |
| static_cast < int >(fBoard->GetNominalFrequency() * 1000)); |
| fileHandle = fopen(fileName, "rb"); |
| if (fileHandle == NULL) { |
| printf("Board %d --> Could not find response calibration file:\n", fBoard->GetBoardSerialNumber()); |
| printf("%s\n", fileName); |
| return false; |
| } |
| if (fInitialized) |
| delete fCalibrationData[chipIndex]; |
| fCalibrationData[chipIndex] = new CalibrationData(1); |
| CalibrationData *data = fCalibrationData[chipIndex]; |
| CalibrationData::CalibrationDataChannel * chn; |
| data->fRead = true; |
| data->fHasOffsetCalibration = 1; |
| fCalibrationValid[chipIndex] = true; |
| data->fStartTemperature = 0; |
| data->fEndTemperature = 0; |
| // read channel |
| for (k = 0; k < kNumberOfCalibChannelsV4; k++) { |
| chn = data->fChannel[k]; |
| for (l = 0; l < kNumberOfBins; l++) { |
| // Offset |
| num = fread(&chn->fOffset[l], 2, 1, fileHandle); |
| if (num != 1) { |
| printf("Error while reading response calibration file '%s'\n", fileName); |
| printf(" at 'Offset' of channel %d bin %d.\n", k, l); |
| return false; |
| } |
| if (fBoard->GetDRSType() == 3) { |
| // Gain |
| num = fread(&chn->fGain[l], 2, 1, fileHandle); |
| if (num != 1) { |
| printf("Error while reading response calibration file '%s'\n", fileName); |
| printf(" at 'Gain' of channel %d bin %d.\n", k, l); |
| return false; |
| } |
| } |
| } |
| } |
| fclose(fileHandle); |
| return true; |
| } |
| /*------------------------------------------------------------------*/ |
| float ResponseCalibration::GetValue(float *coefficients, float u, int n) |
| { |
| int j, ii; |
| float bsplines[4]; |
| ii = CalibrationData::CalculateBSpline(n, u, bsplines); |
| float s = 0; |
| for (j = 0; j < kBSplineOrder; j++) { |
| s += coefficients[ii + j] * bsplines[j]; |
| } |
| return s; |
| } |
| /*------------------------------------------------------------------*/ |
| int ResponseCalibration::Approx(float *p, float *uu, int np, int nu, float *coef) |
| { |
| int i, iu, j; |
| const int mbloc = 50; |
| int ip = 0; |
| int ir = 0; |
| int mt = 0; |
| int ileft, irow; |
| float bu[kBSplineOrder]; |
| float *matrix[kBSplineOrder + 2]; |
| for (i = 0; i < kBSplineOrder + 2; i++) |
| matrix[i] = new float[mbloc + nu + 1]; |
| for (iu = kBSplineOrder - 1; iu < nu; iu++) { |
| for (i = 0; i < np; i++) { |
| if (1 <= uu[i]) |
| ileft = nu - 1; |
| else if (uu[i] < 0) |
| ileft = kBSplineOrder - 2; |
| else |
| ileft = kBSplineOrder - 1 + static_cast < int >(uu[i] * (nu - kBSplineOrder + 1)); |
| if (ileft != iu) |
| continue; |
| irow = ir + mt; |
| mt++; |
| CalibrationData::CalculateBSpline(nu, uu[i], bu); |
| for (j = 0; j < kBSplineOrder; j++) { |
| matrix[j][irow] = bu[j]; |
| } |
| matrix[kBSplineOrder][irow] = p[i]; |
| if (mt < mbloc) |
| continue; |
| LeastSquaresAccumulation(matrix, kBSplineOrder, &ip, &ir, mt, iu - kBSplineOrder + 1); |
| mt = 0; |
| } |
| if (mt == 0) |
| continue; |
| LeastSquaresAccumulation(matrix, kBSplineOrder, &ip, &ir, mt, iu - kBSplineOrder + 1); |
| mt = 0; |
| } |
| if (!LeastSquaresSolving(matrix, kBSplineOrder, ip, ir, coef, nu)) { |
| for (i = 0; i < kBSplineOrder + 2; i++) |
| delete matrix[i]; |
| return 0; |
| } |
| for (i = 0; i < kBSplineOrder + 2; i++) |
| delete matrix[i]; |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| void ResponseCalibration::LeastSquaresAccumulation(float **matrix, int nb, int *ip, int *ir, int mt, int jt) |
| { |
| int i, j, l, mu, k, kh; |
| float rho; |
| if (mt <= 0) |
| return; |
| if (jt != *ip) { |
| if (jt > (*ir)) { |
| for (i = 0; i < mt; i++) { |
| for (j = 0; j < nb + 1; j++) { |
| matrix[j][jt + mt - i] = matrix[j][(*ir) + mt - i]; |
| } |
| } |
| for (i = 0; i < jt - (*ir); i++) { |
| for (j = 0; j < nb + 1; j++) { |
| matrix[j][(*ir) + i] = 0; |
| } |
| } |
| *ir = jt; |
| } |
| mu = min(nb - 1, (*ir) - (*ip) - 1); |
| if (mu != 0) { |
| for (l = 0; l < mu; l++) { |
| k = min(l + 1, jt - (*ip)); |
| for (i = l + 1; i < nb; i++) { |
| matrix[i - k][(*ip) + l + 1] = matrix[i][(*ip) + l + 1]; |
| } |
| for (i = 0; i < k; i++) { |
| matrix[nb - i - 1][(*ip) + l + 1] = 0; |
| } |
| } |
| } |
| *ip = jt; |
| } |
| kh = min(nb + 1, (*ir) + mt - (*ip)); |
| for (i = 0; i < kh; i++) { |
| Housholder(i, max(i + 1, (*ir) - (*ip)), (*ir) + mt - (*ip), matrix, i, (*ip), &rho, matrix, i + 1, |
| (*ip), 1, nb - i); |
| } |
| *ir = (*ip) + kh; |
| if (kh < nb + 1) |
| return; |
| for (i = 0; i < nb; i++) { |
| matrix[i][(*ir) - 1] = 0; |
| } |
| } |
| /*------------------------------------------------------------------*/ |
| int ResponseCalibration::LeastSquaresSolving(float **matrix, int nb, int ip, int ir, float *x, int n) |
| { |
| int i, j, l, ii; |
| float s, rsq; |
| for (j = 0; j < n; j++) { |
| x[j] = matrix[nb][j]; |
| } |
| rsq = 0; |
| if (n <= ir - 1) { |
| for (j = n; j < ir; j++) { |
| rsq += pow(matrix[nb][j], 2); |
| } |
| } |
| for (ii = 0; ii < n; ii++) { |
| i = n - ii - 1; |
| s = 0; |
| l = max(0, i - ip); |
| if (i != n - 1) { |
| for (j = 1; j < min(n - i, nb); j++) { |
| s += matrix[j + l][i] * x[i + j]; |
| } |
| } |
| if (matrix[l][i] == 0) { |
| printf("Error in LeastSquaresSolving.\n"); |
| return 0; |
| } |
| x[i] = (x[i] - s) / matrix[l][i]; |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| void ResponseCalibration::Housholder(int lpivot, int l1, int m, float **u, int iU1, int iU2, float *up, |
| float **c, int iC1, int iC2, int ice, int ncv) |
| { |
| int i, j, incr; |
| float tol = static_cast < float >(1e-20); |
| float tolb = static_cast < float >(1e-24); |
| float cl, clinv, sm, b; |
| if (lpivot < 0 || lpivot >= l1 || l1 > m - 1) |
| return; |
| cl = fabs(u[iU1][iU2 + lpivot]); |
| // Construct the transformation |
| for (j = l1 - 1; j < m; j++) |
| cl = max(fabsf(u[iU1][iU2 + j]), cl); |
| if (cl < tol) |
| return; |
| clinv = 1 / cl; |
| sm = pow(u[iU1][iU2 + lpivot] * clinv, 2); |
| for (j = l1; j < m; j++) { |
| sm = sm + pow(u[iU1][iU2 + j] * clinv, 2); |
| } |
| cl *= sqrt(sm); |
| if (u[iU1][iU2 + lpivot] > 0) |
| cl = -cl; |
| *up = u[iU1][iU2 + lpivot] - cl; |
| u[iU1][iU2 + lpivot] = cl; |
| if (ncv <= 0) |
| return; |
| b = (*up) * u[iU1][iU2 + lpivot]; |
| if (fabs(b) < tolb) |
| return; |
| if (b >= 0) |
| return; |
| b = 1 / b; |
| incr = ice * (l1 - lpivot); |
| for (j = 0; j < ncv; j++) { |
| sm = c[iC1 + j][iC2 + lpivot] * (*up); |
| for (i = l1; i < m; i++) { |
| sm = sm + c[iC1 + j][iC2 + lpivot + incr + (i - l1) * ice] * u[iU1][iU2 + i]; |
| } |
| if (sm == 0) |
| continue; |
| sm *= b; |
| c[iC1 + j][iC2 + lpivot] = c[iC1 + j][iC2 + lpivot] + sm * (*up); |
| for (i = l1; i < m; i++) { |
| c[iC1 + j][iC2 + lpivot + incr + (i - l1) * ice] = |
| c[iC1 + j][iC2 + lpivot + incr + (i - l1) * ice] + sm * u[iU1][iU2 + i]; |
| } |
| } |
| } |
| /*------------------------------------------------------------------*/ |
| int ResponseCalibration::MakeDir(const char *path) |
| { |
| struct stat buf; |
| if (stat(path, &buf)) { |
| #ifdef _MSC_VER |
| return mkdir(path); |
| #else |
| return mkdir(path, 0711); |
| #endif // R__UNIX |
| } |
| return 0; |
| } |
| /*------------------------------------------------------------------*/ |
| ResponseCalibration::ResponseCalibration(DRSBoard * board) |
| : fBoard(board) |
| , fPrecision(0.1) // mV |
| , fInitialized(false) |
| , fRecorded(false) |
| , fFitted(false) |
| , fOffset(false) |
| , fNumberOfPointsLowVolt(0) |
| , fNumberOfPoints(0) |
| , fNumberOfMode2Bins(0) |
| , fNumberOfSamples(0) |
| , fNumberOfGridPoints(0) |
| , fNumberOfXConstPoints(0) |
| , fNumberOfXConstGridPoints(0) |
| , fTriggerFrequency(0) |
| , fShowStatistics(0) |
| , fCalibFile(0) |
| , fCurrentLowVoltPoint(0) |
| , fCurrentPoint(0) |
| , fCurrentSample(0) |
| , fCurrentFitChannel(0) |
| , fCurrentFitBin(0) |
| , fResponseY(0) |
| , fSamples(0) |
| , fSampleUsed(0) |
| , fXXFit(0) |
| , fYYFit(0) |
| , fWWFit(0) |
| , fYYFitRes(0) |
| , fYYSave(0) |
| , fXXSave(0) |
| , fStatisticsApprox(0) |
| , fStatisticsApproxExt(0) |
| { |
| int i; |
| // Initializing the Calibration Class |
| CalibrationData::fIntRevers[0] = 0; |
| for (i = 1; i < 2 * kBSplineOrder - 2; i++) { |
| CalibrationData::fIntRevers[i] = static_cast < float >(1.) / i; |
| } |
| for (i = 0; i < kNumberOfChipsMax; i++) { |
| fCalibrationData[i] = NULL; |
| } |
| // Initializing the Calibration Creation |
| fCalibrationValid[0] = false; |
| fCalibrationValid[1] = false; |
| } |
| /*------------------------------------------------------------------*/ |
| ResponseCalibration::~ResponseCalibration() |
| { |
| // Delete the Calibration |
| for (int i=0 ; i<kNumberOfChipsMax ; i++) |
| delete fCalibrationData[i]; |
| // Deleting the Calibration Creation |
| DeleteFields(); |
| } |
| /*------------------------------------------------------------------*/ |
| float ResponseCalibration::CalibrationData::fIntRevers[2 * kBSplineOrder - 2]; |
| ResponseCalibration::CalibrationData::CalibrationData(int numberOfGridPoints) |
| :fRead(false) |
| , fNumberOfGridPoints(numberOfGridPoints) |
| , fHasOffsetCalibration(0) |
| , fStartTemperature(0) |
| , fEndTemperature(0) |
| , fMin(0) |
| , fMax(0) |
| , fNumberOfLimitGroups(0) |
| { |
| int i; |
| for (i = 0; i < kNumberOfCalibChannelsV3; i++) { |
| fChannel[i] = new CalibrationDataChannel(numberOfGridPoints); |
| } |
| for (i = 0; i < kNumberOfADCBins; i++) { |
| fBSplineOffsetLookUp[i] = NULL; |
| fBSplineLookUp[i] = NULL; |
| } |
| }; |
| /*------------------------------------------------------------------*/ |
| void ResponseCalibration::CalibrationData::PreCalculateBSpline() |
| { |
| int i, j; |
| float uu; |
| float xmin, xrange; |
| int nk = fNumberOfGridPoints - kBSplineOrder + 1; |
| for (i = 0; i < kNumberOfADCBins; i++) { |
| fBSplineLookUp[i] = new float *[fNumberOfLimitGroups]; |
| fBSplineOffsetLookUp[i] = new int[fNumberOfLimitGroups]; |
| for (j = 0; j < fNumberOfLimitGroups; j++) { |
| fBSplineLookUp[i][j] = new float[kBSplineOrder]; |
| xmin = fMin + j * kBSplineXMinOffset; |
| xrange = fMax - xmin; |
| uu = (i - xmin) / xrange; |
| if (i < xmin) { |
| uu = 0; |
| } |
| if (i - xmin > xrange) { |
| uu = 1; |
| } |
| fBSplineOffsetLookUp[i][j] = static_cast < int >(uu * nk); |
| CalculateBSpline(fNumberOfGridPoints, uu, fBSplineLookUp[i][j]); |
| } |
| } |
| } |
| /*------------------------------------------------------------------*/ |
| void ResponseCalibration::CalibrationData::DeletePreCalculatedBSpline() |
| { |
| int i, j; |
| for (i = 0; i < kNumberOfADCBins; i++) { |
| if (fBSplineLookUp[i] != NULL) { |
| for (j = 0; j < fNumberOfLimitGroups; j++) |
| delete fBSplineLookUp[i][j]; |
| } |
| delete fBSplineLookUp[i]; |
| delete fBSplineOffsetLookUp[i]; |
| } |
| } |
| /*------------------------------------------------------------------*/ |
| ResponseCalibration::CalibrationData::~CalibrationData() |
| { |
| int i, j; |
| for (i = 0; i < kNumberOfCalibChannelsV3; i++) { |
| delete fChannel[i]; |
| } |
| for (i = 0; i < kNumberOfADCBins; i++) { |
| if (fBSplineLookUp[i] != NULL) { |
| for (j = 0; j < fNumberOfLimitGroups; j++) { |
| delete fBSplineLookUp[i][j]; |
| } |
| } |
| delete fBSplineLookUp[i]; |
| delete fBSplineOffsetLookUp[i]; |
| } |
| }; |
| /*------------------------------------------------------------------*/ |
| int ResponseCalibration::CalibrationData::CalculateBSpline(int nGrid, float value, float *bsplines) |
| { |
| int minimum; |
| int maximum; |
| float xl; |
| int nk = nGrid - kBSplineOrder + 1; |
| float vl = value * nk; |
| int ivl = static_cast < int >(vl); |
| if (1 <= value) { |
| xl = vl - nk + 1; |
| minimum = 1 - nk; |
| } else if (value < 0) { |
| xl = vl; |
| minimum = 0; |
| } else { |
| xl = vl - ivl; |
| minimum = -ivl; |
| } |
| maximum = nk + minimum; |
| // printf("xl = %f\n",xl); |
| float vm, vmprev; |
| int jl, ju; |
| int nb = 0; |
| bsplines[0] = 1; |
| for (int i = 0; i < kBSplineOrder - 1; i++) { |
| vmprev = 0; |
| for (int j = 0; j < nb + 1; j++) { |
| jl = max(minimum, j - nb); |
| ju = min(maximum, j + 1); |
| vm = bsplines[j] * fIntRevers[ju - jl]; |
| bsplines[j] = vm * (ju - xl) + vmprev; |
| vmprev = vm * (xl - jl); |
| } |
| nb++; |
| bsplines[nb] = vmprev; |
| } |
| return -minimum; |
| } |
| /*------------------------------------------------------------------*/ |
| void ResponseCalibration::Average(int method, float *points, int numberOfPoints, float &mean, float &error, |
| float sigmaBoundary) |
| { |
| // Methods : |
| // 0 : Average |
| // 1 : Average inside sigmaBoundary*sigma |
| int i; |
| float sum = 0; |
| float sumSquare = 0; |
| if (method == 0 || method == 1) { |
| for (i = 0; i < numberOfPoints; i++) { |
| sum += points[i]; |
| sumSquare += points[i] * points[i]; |
| } |
| mean = sum / numberOfPoints; |
| error = sqrt((sumSquare - sum * sum / numberOfPoints) / (numberOfPoints - 1)); |
| } |
| if (method == 1) { |
| int numberOfGoodPoints = numberOfPoints; |
| bool found = true; |
| bool *goodSample = new bool[numberOfGoodPoints]; |
| for (i = 0; i < numberOfGoodPoints; i++) |
| goodSample[i] = true; |
| while (found) { |
| found = false; |
| for (i = 0; i < numberOfPoints; i++) { |
| if (goodSample[i] && fabs(points[i] - mean) > sigmaBoundary * error) { |
| found = true; |
| goodSample[i] = false; |
| numberOfGoodPoints--; |
| sum -= points[i]; |
| sumSquare -= points[i] * points[i]; |
| mean = sum / numberOfGoodPoints; |
| error = sqrt((sumSquare - sum * sum / numberOfGoodPoints) / (numberOfGoodPoints - 1)); |
| } |
| } |
| } |
| delete[] goodSample; |
| } |
| } |
| /cvi/instr/drsctrl/DRS.obj |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |
| /cvi/instr/drsctrl/LinkDef.h |
|---|
| 0,0 → 1,7 |
| #ifdef __CINT__ |
| #pragma link off all globals; |
| #pragma link off all classes; |
| #pragma link C++ function TimerOut; |
| #endif |
| /cvi/instr/drsctrl/Makefile |
|---|
| 0,0 → 1,208 |
| #cmd.exe /k ""C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"" x86 |
| #set INCLUDE=%INCLUDE%;"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include" |
| #set ROOTSYS=C:\root_v5.34.34 |
| # |
| #nmake -f Makefile.win32 |
| # |
| #set INCLUDE=%INCLUDE%;C:\Program Files\Microsoft SDKs\Windows\v7.1A\Include |
| !if "$(CFG)" == "" |
| !if ([findstr /c:"--build=debug" $(ROOTSYS)\bin\root-config > nul ] == 0) |
| CFG = Win32 Debug |
| !if ([findstr /c:"--disable-winrtdebug" $(ROOTSYS)\bin\root-config > nul ] == 0) |
| RUNTIME = Release |
| !else |
| RUNTIME = Debug |
| !endif |
| !message No configuration specified: Defaulting to Win32 Debug |
| !message With $(RUNTIME) Runtime DLL (Taken from ROOT config). |
| !message . |
| !else |
| CFG = Win32 Release |
| RUNTIME = Release |
| !message No configuration specified: Defaulting to Win32 Release |
| !message With $(RUNTIME) Runtime DLL (Taken from ROOT config). |
| !message . |
| !endif |
| !else |
| !if "$(CFG)" == "Win32 Release" |
| RUNTIME = Release |
| !elseif "$(CFG)" == "Win32 Debug" |
| RUNTIME = Debug |
| !endif |
| !endif |
| !if "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug" |
| !message Invalid configuration "$(CFG)" specified. |
| !message You can specify a configuration when running NMAKE |
| !message by defining the macro CFG on the command line. For example: |
| !message |
| !message NMAKE /f "Makefile.msc" CFG="Win32 Debug" |
| !message |
| !message Possible choices for configuration are: |
| !message |
| !message "Win32 Release" (based on "Win32 (x86) Dynamic Library") |
| !message "Win32 Debug" (based on "Win32 (x86) Dynamic Library") |
| !message |
| !error An invalid configuration is specified. |
| !endif |
| !message ROOTSYS = "$(ROOTSYS)/include" |
| ObjSuf = obj |
| SrcSuf = c |
| SrcSuf1 = cpp |
| ExeSuf = .exe |
| DllSuf = dll |
| OutPutOpt = -out: |
| ## VS2012 (VC11): configure subsystem version |
| ## See: https://blogs.msdn.com/b/vcblog/archive/2012/10/08/10357555.aspx |
| ## (APPVER used in win32.mak to set subsystem version) |
| !if ([nmake /? 2>&1 | findstr /c:"Version 14\." > nul ] == 0) |
| APPVER = 5.01 |
| !endif |
| # Win32 system with Microsoft Visual C/C++ |
| !include <win32.mak> |
| CC = $(cc) |
| CXX = $(cc) |
| CXXFLAGS = -nologo -EHsc -GR -DWIN32 -W3 -D_WINDOWS -DMAIN -DDLLMAIN -DHAVE_USB -DHAVE_LIBUSB10 -D_XKEYCHECK_H -DMYDLL_API\ |
| -DVISUAL_CPLUSPLUS -I$(ROOTSYS)/include -Icvi -I. \ |
| -wd4244 |
| #-FIw32pragma.h |
| LD = $(link) |
| !if "$(CFG)" == "Win32 Release" |
| CXXOPT = -O2 -arch:SSE2 -MD |
| LDOPT = -opt:ref |
| !elseif "$(CFG)" == "Win32 Debug" |
| !if "$(RUNTIME)" == "Debug" |
| CXXOPT = -Z7 -MDd |
| !else |
| CXXOPT = -Z7 -O2 -arch:SSE2 -MD |
| !endif |
| LDOPT = -debug |
| !endif |
| # Check if nmake version is 8.xx or 9.xx |
| !if ([nmake /? 2>&1 | findstr /c:"Version 8\." > nul ] == 0) || \ |
| ([nmake /? 2>&1 | findstr /c:"Version 9\." > nul ] == 0) |
| MT_EXE = mt -nologo -manifest $@.manifest -outputresource:$@;1 |
| MT_DLL = mt -nologo -manifest $@.manifest -outputresource:$@;2 |
| EXTRAFLAGS = -D_CRT_SECURE_NO_DEPRECATE |
| !else if ([nmake /? 2>&1 | findstr /c:"Version 12\." > nul ] == 0) |
| MT_EXE = |
| MT_DLL = |
| EXTRAFLAGS = |
| !else if ([nmake /? 2>&1 | findstr /c:"Version 10\." > nul ] == 0) |
| EXTRAFLAGS = -D_CRT_SECURE_NO_DEPRECATE |
| !else if ([nmake /? 2>&1 | findstr /c:"Version 14\." > nul ] == 0) |
| EXTRAFLAGS = -D_CRT_SECURE_NO_DEPRECATE |
| !else |
| MT_EXE = |
| MT_DLL = |
| EXTRAFLAGS = -G5 |
| !endif |
| LDFLAGS1 = $(LDOPT) $(conlflags) -nologo -include:_G__cpp_setupG__Hist \ |
| -include:_G__cpp_setupG__Graf -include:_G__cpp_setupG__G3D \ |
| -include:_G__cpp_setupG__GPad -include:_G__cpp_setupG__Tree \ |
| -include:_G__cpp_setupG__Rint -include:_G__cpp_setupG__PostScript \ |
| -include:_G__cpp_setupG__Matrix -include:_G__cpp_setupG__Physics |
| LDFLAGS1 = $(LDOPT) $(conlflags) -nologo |
| SOFLAGS = $(dlllflags:-pdb:none=) |
| ROOTLIBS = $(ROOTSYS)\lib\libCore.lib \ |
| $(ROOTSYS)\lib\libCint.lib $(ROOTSYS)\lib\libHist.lib \ |
| $(ROOTSYS)\lib\libGraf.lib $(ROOTSYS)\lib\libGraf3d.lib \ |
| $(ROOTSYS)\lib\libGpad.lib $(ROOTSYS)\lib\libTree.lib \ |
| $(ROOTSYS)\lib\libRint.lib $(ROOTSYS)\lib\libPostscript.lib \ |
| $(ROOTSYS)\lib\libMatrix.lib $(ROOTSYS)\lib\libPhysics.lib \ |
| $(ROOTSYS)\lib\libNet.lib $(ROOTSYS)\lib\libRIO.lib \ |
| $(ROOTSYS)\lib\libMathCore.lib |
| LIBS = libusb-1.0.lib |
| GLIBS = $(LIBS) $(ROOTSYS)\lib\libGui.lib $(ROOTSYS)\lib\libGraf.lib \ |
| $(ROOTSYS)\lib\libGpad.lib |
| LIBSALL = libusb-1.0.lib |
| #------------------------------------------------------------------------------ |
| MYAPP = drscl$(ExeSuf) |
| MYAPPS = drscl.$(SrcSuf1) musbstd.$(SrcSuf) mxml.$(SrcSuf) strlcpy.$(SrcSuf) DRS.$(SrcSuf1) averager.$(SrcSuf1) |
| MYAPPO = drscl.$(ObjSuf) musbstd.$(ObjSuf) mxml.$(ObjSuf) strlcpy.$(ObjSuf) DRS.$(ObjSuf) averager.$(ObjSuf) |
| MYREADO = musbstd.$(ObjSuf) mxml.$(ObjSuf) DRS.$(ObjSuf) averager.$(ObjSuf) drsread.$(ObjSuf) XGetopt.$(ObjSuf) getopt_long.$(ObjSuf) timer.$(ObjSuf) gettimeofday.$(ObjSuf) |
| OBJS = $(MYAPPO) |
| PROGRAMS = $(MYAPP) |
| #------------------------------------------------------------------------------ |
| !message LDFLAGS = "$(LDFLAGS)" |
| !message MYAPP = "$(MYAPP)" |
| !message MYAPPO = "$(MYAPPO)" |
| !message PROGRAMS = "$(PROGRAMS)" |
| all: $(PROGRAMS) drsread.exe drsread.dll |
| RootShowerDict.$(SrcSuf): MyParticle.h MyDetector.h MyEvent.h RSLinkDef.h |
| @echo "Generating dictionary $@..." |
| @rootcint -f $@ -c MyParticle.h MyDetector.h MyEvent.h RSLinkDef.h |
| #------------------------------------------------------------------------------ |
| clean: |
| @del *.obj *Dict.* *.def *.exp *.d *.log .def *.pdb *.ilk *.manifest |
| distclean: clean |
| @del *.exe *.root *.ps *.lib *.dll |
| $(MYAPP): $(MYAPPO) |
| @echo "Compiling $@ " |
| $(LD) $(LDFLAGS) /SUBSYSTEM:CONSOLE \ |
| $(MYAPPO) $(LIBSALL) $(OutPutOpt)$@ |
| @echo "$@ done" |
| drscl.$(ObjSuf): drscl.$(SrcSuf1) |
| @echo "Compiling drs $@ " |
| $(CXX) $(CXXFLAGS) $(EXTRAFLAGS) $(CXXOPT) -c drscl.$(SrcSuf1) |
| drsread.exe: $(MYREADO) |
| @echo "Compiling $@ " |
| $(LD) $(LDFLAGS) /SUBSYSTEM:CONSOLE \ |
| $(MYREADO) $(LIBSALL) $(ROOTLIBS) $(OutPutOpt)$@ |
| @echo "$@ done" |
| drsread.dll: $(MYREADO) |
| @echo "DLL library $@ " |
| $(LD) /DLL $(MYREADO) $(LIBSALL) $(ROOTLIBS) /OUT:drsread.dll |
| @echo "$@ done" |
| drsreadDict.cpp: drsread.h LinkDef.h |
| rootcint -f drsreadDict.cpp -c drsread.h LinkDef.h |
| drsread.$(ObjSuf): drsread.$(SrcSuf1) |
| @echo "Compiling drsread $@ " |
| $(CXX) $(CXXFLAGS) $(EXTRAFLAGS) $(CXXOPT) -c drsread.$(SrcSuf1) |
| drsread.$(ObjSuf): drsread.$(SrcSuf1) |
| @echo "Compiling drsread $@ " |
| $(CXX) $(CXXFLAGS) $(EXTRAFLAGS) $(CXXOPT) -c drsread.$(SrcSuf1) |
| .$(SrcSuf1).$(ObjSuf): |
| @echo "Compiling object $@ " |
| $(CXX) $(CXXFLAGS) $(EXTRAFLAGS) $(CXXOPT) -c $< |
| .c.$(ObjSuf): |
| @echo "Compiling object $@ " |
| $(CXX) $(CXXFLAGS) $(EXTRAFLAGS) $(CXXOPT) -c $< |
| /cvi/instr/drsctrl/XGetopt.cpp |
|---|
| 0,0 → 1,225 |
| // XGetopt.cpp Version 1.2 |
| // |
| // Author: Hans Dietrich |
| // hdietrich2@hotmail.com |
| // |
| // Description: |
| // XGetopt.cpp implements getopt(), a function to parse command lines. |
| // |
| // History |
| // Version 1.2 - 2003 May 17 |
| // - Added Unicode support |
| // |
| // Version 1.1 - 2002 March 10 |
| // - Added example to XGetopt.cpp module header |
| // |
| // This software is released into the public domain. |
| // You are free to use it in any way you like. |
| // |
| // This software is provided "as is" with no expressed |
| // or implied warranty. I accept no liability for any |
| // damage or loss of business that this software may cause. |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| /////////////////////////////////////////////////////////////////////////////// |
| // if you are using precompiled headers then include this line: |
| //#include "stdafx.h" |
| /////////////////////////////////////////////////////////////////////////////// |
| /////////////////////////////////////////////////////////////////////////////// |
| // if you are not using precompiled headers then include these lines: |
| #include <windows.h> |
| #include <stdio.h> |
| #include <tchar.h> |
| /////////////////////////////////////////////////////////////////////////////// |
| #include "XGetopt.h" |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // X G e t o p t . c p p |
| // |
| // |
| // NAME |
| // getopt -- parse command line options |
| // |
| // SYNOPSIS |
| // int getopt(int argc, TCHAR *argv[], TCHAR *optstring) |
| // |
| // extern TCHAR *optarg; |
| // extern int optind; |
| // |
| // DESCRIPTION |
| // The getopt() function parses the command line arguments. Its |
| // arguments argc and argv are the argument count and array as |
| // passed into the application on program invocation. In the case |
| // of Visual C++ programs, argc and argv are available via the |
| // variables __argc and __argv (double underscores), respectively. |
| // getopt returns the next option letter in argv that matches a |
| // letter in optstring. (Note: Unicode programs should use |
| // __targv instead of __argv. Also, all character and string |
| // literals should be enclosed in _T( ) ). |
| // |
| // optstring is a string of recognized option letters; if a letter |
| // is followed by a colon, the option is expected to have an argument |
| // that may or may not be separated from it by white space. optarg |
| // is set to point to the start of the option argument on return from |
| // getopt. |
| // |
| // Option letters may be combined, e.g., "-ab" is equivalent to |
| // "-a -b". Option letters are case sensitive. |
| // |
| // getopt places in the external variable optind the argv index |
| // of the next argument to be processed. optind is initialized |
| // to 0 before the first call to getopt. |
| // |
| // When all options have been processed (i.e., up to the first |
| // non-option argument), getopt returns EOF, optarg will point |
| // to the argument, and optind will be set to the argv index of |
| // the argument. If there are no non-option arguments, optarg |
| // will be set to NULL. |
| // |
| // The special option "--" may be used to delimit the end of the |
| // options; EOF will be returned, and "--" (and everything after it) |
| // will be skipped. |
| // |
| // RETURN VALUE |
| // For option letters contained in the string optstring, getopt |
| // will return the option letter. getopt returns a question mark (?) |
| // when it encounters an option letter not included in optstring. |
| // EOF is returned when processing is finished. |
| // |
| // BUGS |
| // 1) Long options are not supported. |
| // 2) The GNU double-colon extension is not supported. |
| // 3) The environment variable POSIXLY_CORRECT is not supported. |
| // 4) The + syntax is not supported. |
| // 5) The automatic permutation of arguments is not supported. |
| // 6) This implementation of getopt() returns EOF if an error is |
| // encountered, instead of -1 as the latest standard requires. |
| // |
| // EXAMPLE |
| // BOOL CMyApp::ProcessCommandLine(int argc, TCHAR *argv[]) |
| // { |
| // int c; |
| // |
| // while ((c = getopt(argc, argv, _T("aBn:"))) != EOF) |
| // { |
| // switch (c) |
| // { |
| // case _T('a'): |
| // TRACE(_T("option a\n")); |
| // // |
| // // set some flag here |
| // // |
| // break; |
| // |
| // case _T('B'): |
| // TRACE( _T("option B\n")); |
| // // |
| // // set some other flag here |
| // // |
| // break; |
| // |
| // case _T('n'): |
| // TRACE(_T("option n: value=%d\n"), atoi(optarg)); |
| // // |
| // // do something with value here |
| // // |
| // break; |
| // |
| // case _T('?'): |
| // TRACE(_T("ERROR: illegal option %s\n"), argv[optind-1]); |
| // return FALSE; |
| // break; |
| // |
| // default: |
| // TRACE(_T("WARNING: no handler for option %c\n"), c); |
| // return FALSE; |
| // break; |
| // } |
| // } |
| // // |
| // // check for non-option args here |
| // // |
| // return TRUE; |
| // } |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| //TCHAR *optarg; // global argument pointer |
| char *optarg; // global argument pointer |
| int optind = 0; // global argv index |
| //int getopt(int argc, TCHAR *argv[], TCHAR *optstring) |
| int getopt(int argc, char *argv[], char *optstring) |
| { |
| //static TCHAR *next = NULL; |
| static char *next = NULL; |
| if (optind == 0) |
| next = NULL; |
| optarg = NULL; |
| if (next == NULL || *next == _T('\0')) |
| { |
| if (optind == 0) |
| optind++; |
| if (optind >= argc || argv[optind][0] != _T('-') || argv[optind][1] == _T('\0')) |
| { |
| optarg = NULL; |
| if (optind < argc) |
| optarg = argv[optind]; |
| return EOF; |
| } |
| if (strcmp( argv[optind], _T("--")) == 0) |
| { |
| optind++; |
| optarg = NULL; |
| if (optind < argc) |
| optarg = argv[optind]; |
| return EOF; |
| } |
| next = argv[optind]; |
| next++; // skip past - |
| optind++; |
| } |
| //TCHAR c = *next++; |
| //TCHAR *cp = _tcschr(optstring, c); |
| char c = *next++; |
| //char *cp = _tcschr(optstring, c); |
| char *cp =strchr(optstring, c); |
| if (cp == NULL || c == _T(':')) |
| return _T('?'); |
| cp++; |
| if (*cp == _T(':')) |
| { |
| if (*next != _T('\0')) |
| { |
| optarg = next; |
| next = NULL; |
| } |
| else if (optind < argc) |
| { |
| optarg = argv[optind]; |
| optind++; |
| } |
| else |
| { |
| return _T('?'); |
| } |
| } |
| return c; |
| } |
| /cvi/instr/drsctrl/XGetopt.h |
|---|
| 0,0 → 1,25 |
| // XGetopt.h Version 1.2 |
| // |
| // Author: Hans Dietrich |
| // hdietrich2@hotmail.com |
| // |
| // This software is released into the public domain. |
| // You are free to use it in any way you like. |
| // |
| // This software is provided "as is" with no expressed |
| // or implied warranty. I accept no liability for any |
| // damage or loss of business that this software may cause. |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| #ifndef XGETOPT_H |
| #define XGETOPT_H |
| extern int optind, opterr; |
| //extern TCHAR *optarg; |
| extern char *optarg; |
| //int getopt(int argc, TCHAR *argv[], TCHAR *optstring); |
| int getopt(int argc, char *argv[], char *optstring); |
| #endif //XGETOPT_H |
| /cvi/instr/drsctrl/XGetopt.obj |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |
| /cvi/instr/drsctrl/averager.cpp |
|---|
| 0,0 → 1,214 |
| /********************************************************************\ |
| Name: averager.cpp |
| Created by: Stefan Ritt |
| Contents: Robust averager |
| $Id: averager.cpp 21210 2013-12-12 11:36:59Z ritt $ |
| \********************************************************************/ |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <math.h> |
| #include <assert.h> |
| #include "averager.h" |
| /*----------------------------------------------------------------*/ |
| Averager::Averager(int nx, int ny, int nz, int dim) |
| { |
| fNx = nx; |
| fNy = ny; |
| fNz = nz; |
| fDim = dim; |
| int size = sizeof(float)*nx*ny*nz * dim; |
| fArray = (float *)malloc(size); |
| assert(fArray); |
| memset(fArray, 0, size); |
| size = sizeof(float)*nx*ny*nz; |
| fN = (unsigned short *)malloc(size); |
| assert(fN); |
| memset(fN, 0, size); |
| } |
| /*----------------------------------------------------------------*/ |
| Averager::~Averager() |
| { |
| if (fN) |
| free(fN); |
| if (fArray) |
| free(fArray); |
| fN = NULL; |
| fArray = NULL; |
| } |
| /*----------------------------------------------------------------*/ |
| void Averager::Add(int x, int y, int z, float value) |
| { |
| assert(x < fNx); |
| assert(y < fNy); |
| assert(z < fNz); |
| int nIndex = (x*fNy + y)*fNz + z; |
| if (fN[nIndex] == fDim - 1) // check if array full |
| return; |
| int aIndex = ((x*fNy + y)*fNz + z) * fDim + fN[nIndex]; |
| fN[nIndex]++; |
| fArray[aIndex] = value; |
| } |
| /*----------------------------------------------------------------*/ |
| void Averager::Reset() |
| { |
| int size = sizeof(float)*fNx*fNy*fNz * fDim; |
| memset(fArray, 0, size); |
| size = sizeof(float)*fNx*fNy*fNz; |
| memset(fN, 0, size); |
| } |
| /*----------------------------------------------------------------*/ |
| int compar(const void *a, const void *b); |
| int compar(const void *a, const void *b) |
| { |
| if (*((float *)a) == *((float *)b)) |
| return 0; |
| return (*((float *)a) < *((float *)b)) ? -1 : 1; |
| } |
| double Averager::Average(int x, int y, int z) |
| { |
| assert(x < fNx); |
| assert(y < fNy); |
| assert(z < fNz); |
| double a = 0; |
| int nIndex = (x*fNy + y)*fNz + z; |
| int aIndex = ((x*fNy + y)*fNz + z) * fDim; |
| for (int i=0 ; i<fN[nIndex] ; i++) |
| a += fArray[aIndex + i]; |
| if (fN[nIndex] > 0) |
| a /= fN[nIndex]; |
| return a; |
| } |
| /*----------------------------------------------------------------*/ |
| double Averager::Median(int x, int y, int z) |
| { |
| assert(x < fNx); |
| assert(y < fNy); |
| assert(z < fNz); |
| double m = 0; |
| int nIndex = (x*fNy + y)*fNz + z; |
| int aIndex = ((x*fNy + y)*fNz + z) * fDim; |
| qsort(&fArray[aIndex], fN[nIndex], sizeof(float), compar); |
| m = fArray[aIndex + fN[nIndex]/2]; |
| return m; |
| } |
| /*----------------------------------------------------------------*/ |
| double Averager::RobustAverage(double range, int x, int y, int z) |
| { |
| assert(x < fNx); |
| assert(y < fNy); |
| assert(z < fNz); |
| double ra = 0; |
| int n = 0; |
| double m = Median(x, y, z); |
| int nIndex = (x*fNy + y)*fNz + z; |
| int aIndex = ((x*fNy + y)*fNz + z) * fDim; |
| for (int i=0 ; i<fN[nIndex] ; i++) { |
| if (fArray[aIndex + i] > m - range && fArray[aIndex + i] < m + range) { |
| ra += fArray[aIndex + i]; |
| n++; |
| } |
| } |
| if (n > 0) |
| ra /= n; |
| //if (y == 0 && z == 7 && fN[nIndex] > 10) |
| // printf("%d %lf %lf %lf\n", fN[nIndex], a, m, ra); |
| return ra; |
| } |
| /*----------------------------------------------------------------*/ |
| int Averager::SaveNormalizedDistribution(const char *filename, int x, float range) |
| { |
| assert(x < fNx); |
| FILE *f = fopen(filename, "wt"); |
| if (!f) |
| return 0; |
| fprintf(f, "X, Y, Z, Min, Max, Ave, Sigma\n"); |
| for (int y=0 ; y<fNy ; y++) |
| for (int z=0 ; z<fNz ; z++) { |
| int nIndex = (x*fNy + y)*fNz + z; |
| int aIndex = ((x*fNy + y)*fNz + z) * fDim; |
| if (fN[nIndex] > 1) { |
| fprintf(f, "%d,%d, %d, ", x, y, z); |
| double s = 0; |
| double s2 = 0; |
| double min = 0; |
| double max = 0; |
| int n = fN[nIndex]; |
| double m = Median(x, y, z); |
| for (int i=0 ; i<n ; i++) { |
| double v = fArray[aIndex + i] - m; |
| s += v; |
| s2 += v*v; |
| if (v < min) |
| min = v; |
| if (v > max) |
| max = v; |
| } |
| double sigma = sqrt((n * s2 - s * s) / (n * (n-1))); |
| double average = s / n; |
| fprintf(f, "%3.1lf, %3.1lf, %3.1lf, %3.3lf, ", min, max, average, sigma); |
| if (min < -range || max > range) { |
| for (int i=0 ; i<n ; i++) |
| fprintf(f, "%3.1lf,", fArray[aIndex + i] - m); |
| } |
| fprintf(f, "\n"); |
| } |
| } |
| fclose(f); |
| return 1; |
| } |
| /cvi/instr/drsctrl/averager.h |
|---|
| 0,0 → 1,28 |
| /********************************************************************\ |
| Name: averager.h |
| Created by: Stefan Ritt |
| Contents: Robust averager |
| $Id: averager.h 21220 2013-12-20 13:47:43Z ritt $ |
| \********************************************************************/ |
| class Averager { |
| int fNx, fNy, fNz, fDim; |
| float *fArray; |
| unsigned short *fN; |
| public: |
| Averager(int nx, int ny, int nz, int dim); |
| ~Averager(); |
| void Add(int x, int y, int z, float value); |
| void Reset(); |
| double Average(int x, int y, int z); |
| double Median(int x, int y, int z); |
| double RobustAverage(double range, int x, int y, int z); |
| int SaveNormalizedDistribution(const char *filename, int x, float range); |
| }; |
| /cvi/instr/drsctrl/averager.obj |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |
| /cvi/instr/drsctrl/daq.h |
|---|
| 0,0 → 1,18 |
| #ifndef _daq_h_ |
| #define _daq_h_ |
| #define BUFF_L 2048 |
| class daq { |
| public: |
| unsigned long stackwrite[BUFF_L],stackdata[10000],stackdump[27000]; |
| int debug; |
| int fStop; |
| int event(unsigned int *, int); |
| int init(); |
| int connect(); |
| int disconnect(); |
| daq(); |
| ~daq(); |
| }; |
| #endif |
| /cvi/instr/drsctrl/drs.h |
|---|
| 0,0 → 1,950 |
| /******************************************************************** |
| DRS.h, S.Ritt, M. Schneebeli - PSI |
| $Id: DRS.h 21309 2014-04-11 14:51:29Z ritt $ |
| ********************************************************************/ |
| #ifndef DRS_H |
| #define DRS_H |
| #include <stdio.h> |
| #include <string.h> |
| #include "averager.h" |
| #ifdef HAVE_LIBUSB |
| # ifndef HAVE_USB |
| # define HAVE_USB |
| # endif |
| #endif |
| #ifdef HAVE_USB |
| # include "musbstd.h" |
| #endif // HAVE_USB |
| #ifdef HAVE_VME |
| # include <mvmestd.h> |
| #endif // HAVE_VME |
| /* disable "deprecated" warning */ |
| #ifdef _MSC_VER |
| #pragma warning(disable: 4996) |
| #endif |
| #ifndef NULL |
| #define NULL 0 |
| #endif |
| int drs_kbhit(); |
| unsigned int millitime(); |
| /* transport mode */ |
| #define TR_VME 1 |
| #define TR_USB 2 |
| #define TR_USB2 3 |
| /* address types */ |
| #ifndef T_CTRL |
| #define T_CTRL 1 |
| #define T_STATUS 2 |
| #define T_RAM 3 |
| #define T_FIFO 4 |
| #endif |
| /*---- Register addresses ------------------------------------------*/ |
| #define REG_CTRL 0x00000 /* 32 bit control reg */ |
| #define REG_DAC_OFS 0x00004 |
| #define REG_DAC0 0x00004 |
| #define REG_DAC1 0x00006 |
| #define REG_DAC2 0x00008 |
| #define REG_DAC3 0x0000A |
| #define REG_DAC4 0x0000C |
| #define REG_DAC5 0x0000E |
| #define REG_DAC6 0x00010 |
| #define REG_DAC7 0x00012 |
| #define REG_CHANNEL_CONFIG 0x00014 // low byte |
| #define REG_CONFIG 0x00014 // high byte |
| #define REG_CHANNEL_MODE 0x00016 |
| #define REG_ADCCLK_PHASE 0x00016 |
| #define REG_FREQ_SET_HI 0x00018 // DRS2 |
| #define REG_FREQ_SET_LO 0x0001A // DRS2 |
| #define REG_TRG_DELAY 0x00018 // DRS4 |
| #define REG_FREQ_SET 0x0001A // DRS4 |
| #define REG_TRIG_DELAY 0x0001C |
| #define REG_LMK_MSB 0x0001C // DRS4 Mezz |
| #define REG_CALIB_TIMING 0x0001E // DRS2 |
| #define REG_EEPROM_PAGE_EVAL 0x0001E // DRS4 Eval |
| #define REG_EEPROM_PAGE_MEZZ 0x0001A // DRS4 Mezz |
| #define REG_TRG_CONFIG 0x0001C // DRS4 Eval4 |
| #define REG_LMK_LSB 0x0001E // DRS4 Mezz |
| #define REG_WARMUP 0x00020 // DRS4 Mezz |
| #define REG_COOLDOWN 0x00022 // DRS4 Mezz |
| #define REG_READ_POINTER 0x00026 // DRS4 Mezz |
| #define REG_MAGIC 0x00000 |
| #define REG_BOARD_TYPE 0x00002 |
| #define REG_STATUS 0x00004 |
| #define REG_RDAC_OFS 0x0000E |
| #define REG_RDAC0 0x00008 |
| #define REG_STOP_CELL0 0x00008 |
| #define REG_RDAC1 0x0000A |
| #define REG_STOP_CELL1 0x0000A |
| #define REG_RDAC2 0x0000C |
| #define REG_STOP_CELL2 0x0000C |
| #define REG_RDAC3 0x0000E |
| #define REG_STOP_CELL3 0x0000E |
| #define REG_RDAC4 0x00000 |
| #define REG_RDAC5 0x00002 |
| #define REG_STOP_WSR0 0x00010 |
| #define REG_STOP_WSR1 0x00011 |
| #define REG_STOP_WSR2 0x00012 |
| #define REG_STOP_WSR3 0x00013 |
| #define REG_RDAC6 0x00014 |
| #define REG_RDAC7 0x00016 |
| #define REG_EVENTS_IN_FIFO 0x00018 |
| #define REG_EVENT_COUNT 0x0001A |
| #define REG_FREQ1 0x0001C |
| #define REG_FREQ2 0x0001E |
| #define REG_WRITE_POINTER 0x0001E |
| #define REG_TEMPERATURE 0x00020 |
| #define REG_TRIGGER_BUS 0x00022 |
| #define REG_SERIAL_BOARD 0x00024 |
| #define REG_VERSION_FW 0x00026 |
| #define REG_SCALER0 0x00028 |
| #define REG_SCALER1 0x0002C |
| #define REG_SCALER2 0x00030 |
| #define REG_SCALER3 0x00034 |
| #define REG_SCALER4 0x00038 |
| #define REG_SCALER5 0x0003C |
| /*---- Control register bit definitions ----------------------------*/ |
| #define BIT_START_TRIG (1<<0) // write a "1" to start domino wave |
| #define BIT_REINIT_TRIG (1<<1) // write a "1" to stop & reset DRS |
| #define BIT_SOFT_TRIG (1<<2) // write a "1" to stop and read data to RAM |
| #define BIT_EEPROM_WRITE_TRIG (1<<3) // write a "1" to write into serial EEPROM |
| #define BIT_EEPROM_READ_TRIG (1<<4) // write a "1" to read from serial EEPROM |
| #define BIT_MULTI_BUFFER (1<<16) // Use multi buffering when "1" |
| #define BIT_DMODE (1<<17) // (*DRS2*) 0: single shot, 1: circular |
| #define BIT_ADC_ACTIVE (1<<17) // (*DRS4*) 0: stop ADC when running, 1: ADC always clocked |
| #define BIT_LED (1<<18) // 1=on, 0=blink during readout |
| #define BIT_TCAL_EN (1<<19) // switch on (1) / off (0) for 33 MHz calib signal |
| #define BIT_TCAL_SOURCE (1<<20) |
| #define BIT_REFCLK_SOURCE (1<<20) |
| #define BIT_FREQ_AUTO_ADJ (1<<21) // DRS2/3 |
| #define BIT_TRANSP_MODE (1<<21) // DRS4 |
| #define BIT_ENABLE_TRIGGER1 (1<<22) // External LEMO/FP/TRBUS trigger |
| #define BIT_LONG_START_PULSE (1<<23) // (*DRS2*) 0:short start pulse (>0.8GHz), 1:long start pulse (<0.8GHz) |
| #define BIT_READOUT_MODE (1<<23) // (*DRS3*,*DRS4*) 0:start from first bin, 1:start from domino stop |
| #define BIT_DELAYED_START (1<<24) // DRS2: start domino wave 400ns after soft trigger, used for waveform |
| // generator startup |
| #define BIT_NEG_TRIGGER (1<<24) // DRS4: use high-to-low trigger if set |
| #define BIT_ACAL_EN (1<<25) // connect DRS to inputs (0) or to DAC6 (1) |
| #define BIT_TRIGGER_DELAYED (1<<26) // select delayed trigger from trigger bus |
| #define BIT_ADCCLK_INVERT (1<<26) // invert ADC clock |
| #define BIT_REFCLK_EXT (1<<26) // use external MMCX CLKIN refclk |
| #define BIT_DACTIVE (1<<27) // keep domino wave running during readout |
| #define BIT_STANDBY_MODE (1<<28) // put chip in standby mode |
| #define BIT_TR_SOURCE1 (1<<29) // trigger source selection bits |
| #define BIT_DECIMATION (1<<29) // drop all odd samples (DRS4 mezz.) |
| #define BIT_TR_SOURCE2 (1<<30) // trigger source selection bits |
| #define BIT_ENABLE_TRIGGER2 (1<<31) // analog threshold (internal) trigger |
| /* DRS4 configuration register bit definitions */ |
| #define BIT_CONFIG_DMODE (1<<8) // 0: single shot, 1: circular |
| #define BIT_CONFIG_PLLEN (1<<9) // write a "1" to enable the internal PLL |
| #define BIT_CONFIG_WSRLOOP (1<<10) // write a "1" to connect WSROUT to WSRIN internally |
| /*---- Status register bit definitions -----------------------------*/ |
| #define BIT_RUNNING (1<<0) // one if domino wave running or readout in progress |
| #define BIT_NEW_FREQ1 (1<<1) // one if new frequency measurement available |
| #define BIT_NEW_FREQ2 (1<<2) |
| #define BIT_PLL_LOCKED0 (1<<1) // 1 if PLL has locked (DRS4 evaluation board only) |
| #define BIT_PLL_LOCKED1 (1<<2) // 1 if PLL DRS4 B has locked (DRS4 mezzanine board only) |
| #define BIT_PLL_LOCKED2 (1<<3) // 1 if PLL DRS4 C has locked (DRS4 mezzanine board only) |
| #define BIT_PLL_LOCKED3 (1<<4) // 1 if PLL DRS4 D has locked (DRS4 mezzanine board only) |
| #define BIT_SERIAL_BUSY (1<<5) // 1 if EEPROM operation in progress |
| #define BIT_LMK_LOCKED (1<<6) // 1 if PLL of LMK chip has locked (DRS4 mezzanine board only) |
| #define BIT_2048_MODE (1<<7) // 1 if 2048-bin mode has been soldered |
| enum DRSBoardConstants { |
| kNumberOfChannelsMax = 10, |
| kNumberOfCalibChannelsV3 = 10, |
| kNumberOfCalibChannelsV4 = 8, |
| kNumberOfBins = 1024, |
| kNumberOfChipsMax = 4, |
| kFrequencyCacheSize = 10, |
| kBSplineOrder = 4, |
| kPreCaliculatedBSplines = 1000, |
| kPreCaliculatedBSplineGroups = 5, |
| kNumberOfADCBins = 4096, |
| kBSplineXMinOffset = 20, |
| kMaxNumberOfClockCycles = 100, |
| }; |
| enum DRSErrorCodes { |
| kSuccess = 0, |
| kInvalidTriggerSignal = -1, |
| kWrongChannelOrChip = -2, |
| kInvalidTransport = -3, |
| kZeroSuppression = -4, |
| kWaveNotAvailable = -5 |
| }; |
| /*---- callback class ----*/ |
| class DRSCallback |
| { |
| public: |
| virtual void Progress(int value) = 0; |
| virtual ~DRSCallback() {}; |
| }; |
| /*------------------------*/ |
| class DRSBoard; |
| class ResponseCalibration { |
| protected: |
| class CalibrationData { |
| public: |
| class CalibrationDataChannel { |
| public: |
| unsigned char fLimitGroup[kNumberOfBins]; //! |
| float fMin[kNumberOfBins]; //! |
| float fRange[kNumberOfBins]; //! |
| short fOffset[kNumberOfBins]; //! |
| short fGain[kNumberOfBins]; //! |
| unsigned short fOffsetADC[kNumberOfBins]; //! |
| short *fData[kNumberOfBins]; //! |
| unsigned char *fLookUp[kNumberOfBins]; //! |
| unsigned short fLookUpOffset[kNumberOfBins]; //! |
| unsigned char fNumberOfLookUpPoints[kNumberOfBins]; //! |
| float *fTempData; //! |
| private: |
| CalibrationDataChannel(const CalibrationDataChannel &c); // not implemented |
| CalibrationDataChannel &operator=(const CalibrationDataChannel &rhs); // not implemented |
| public: |
| CalibrationDataChannel(int numberOfGridPoints) |
| :fTempData(new float[numberOfGridPoints]) { |
| int i; |
| for (i = 0; i < kNumberOfBins; i++) { |
| fData[i] = new short[numberOfGridPoints]; |
| } |
| memset(fLimitGroup, 0, sizeof(fLimitGroup)); |
| memset(fMin, 0, sizeof(fMin)); |
| memset(fRange, 0, sizeof(fRange)); |
| memset(fOffset, 0, sizeof(fOffset)); |
| memset(fGain, 0, sizeof(fGain)); |
| memset(fOffsetADC, 0, sizeof(fOffsetADC)); |
| memset(fLookUp, 0, sizeof(fLookUp)); |
| memset(fLookUpOffset, 0, sizeof(fLookUpOffset)); |
| memset(fNumberOfLookUpPoints, 0, sizeof(fNumberOfLookUpPoints)); |
| } |
| ~CalibrationDataChannel() { |
| int i; |
| delete fTempData; |
| for (i = 0; i < kNumberOfBins; i++) { |
| delete fData[i]; |
| delete fLookUp[i]; |
| } |
| } |
| }; |
| bool fRead; //! |
| CalibrationDataChannel *fChannel[10]; //! |
| unsigned char fNumberOfGridPoints; //! |
| int fHasOffsetCalibration; //! |
| float fStartTemperature; //! |
| float fEndTemperature; //! |
| int *fBSplineOffsetLookUp[kNumberOfADCBins]; //! |
| float **fBSplineLookUp[kNumberOfADCBins]; //! |
| float fMin; //! |
| float fMax; //! |
| unsigned char fNumberOfLimitGroups; //! |
| static float fIntRevers[2 * kBSplineOrder - 2]; |
| private: |
| CalibrationData(const CalibrationData &c); // not implemented |
| CalibrationData &operator=(const CalibrationData &rhs); // not implemented |
| public: |
| CalibrationData(int numberOfGridPoints); |
| ~CalibrationData(); |
| static int CalculateBSpline(int nGrid, float value, float *bsplines); |
| void PreCalculateBSpline(); |
| void DeletePreCalculatedBSpline(); |
| }; |
| // General Fields |
| DRSBoard *fBoard; |
| double fPrecision; |
| // Fields for creating the Calibration |
| bool fInitialized; |
| bool fRecorded; |
| bool fFitted; |
| bool fOffset; |
| bool fCalibrationValid[2]; |
| int fNumberOfPointsLowVolt; |
| int fNumberOfPoints; |
| int fNumberOfMode2Bins; |
| int fNumberOfSamples; |
| int fNumberOfGridPoints; |
| int fNumberOfXConstPoints; |
| int fNumberOfXConstGridPoints; |
| double fTriggerFrequency; |
| int fShowStatistics; |
| FILE *fCalibFile; |
| int fCurrentLowVoltPoint; |
| int fCurrentPoint; |
| int fCurrentSample; |
| int fCurrentFitChannel; |
| int fCurrentFitBin; |
| float *fResponseX[10][kNumberOfBins]; |
| float *fResponseY; |
| unsigned short **fWaveFormMode3[10]; |
| unsigned short **fWaveFormMode2[10]; |
| short **fWaveFormOffset[10]; |
| unsigned short **fWaveFormOffsetADC[10]; |
| unsigned short *fSamples; |
| int *fSampleUsed; |
| float *fPntX[2]; |
| float *fPntY[2]; |
| float *fUValues[2]; |
| float *fRes[kNumberOfBins]; |
| float *fResX[kNumberOfBins]; |
| double *fXXFit; |
| double *fYYFit; |
| double *fWWFit; |
| double *fYYFitRes; |
| double *fYYSave; |
| double *fXXSave; |
| double fGainMin; |
| double fGainMax; |
| float **fStatisticsApprox; |
| float **fStatisticsApproxExt; |
| // Fields for applying the Calibration |
| CalibrationData *fCalibrationData[kNumberOfChipsMax]; |
| private: |
| ResponseCalibration(const ResponseCalibration &c); // not implemented |
| ResponseCalibration &operator=(const ResponseCalibration &rhs); // not implemented |
| public: |
| ResponseCalibration(DRSBoard* board); |
| ~ResponseCalibration(); |
| void SetCalibrationParameters(int numberOfPointsLowVolt, int numberOfPoints, int numberOfMode2Bins, |
| int numberOfSamples, int numberOfGridPoints, int numberOfXConstPoints, |
| int numberOfXConstGridPoints, double triggerFrequency, int showStatistics = 0); |
| void ResetCalibration(); |
| bool RecordCalibrationPoints(int chipNumber); |
| bool RecordCalibrationPointsV3(int chipNumber); |
| bool RecordCalibrationPointsV4(int chipNumber); |
| bool FitCalibrationPoints(int chipNumber); |
| bool FitCalibrationPointsV3(int chipNumber); |
| bool FitCalibrationPointsV4(int chipNumber); |
| bool OffsetCalibration(int chipNumber); |
| bool OffsetCalibrationV3(int chipNumber); |
| bool OffsetCalibrationV4(int chipNumber); |
| double GetTemperature(unsigned int chipIndex); |
| bool WriteCalibration(unsigned int chipIndex); |
| bool WriteCalibrationV3(unsigned int chipIndex); |
| bool WriteCalibrationV4(unsigned int chipIndex); |
| bool ReadCalibration(unsigned int chipIndex); |
| bool ReadCalibrationV3(unsigned int chipIndex); |
| bool ReadCalibrationV4(unsigned int chipIndex); |
| bool Calibrate(unsigned int chipIndex, unsigned int channel, unsigned short *adcWaveform, short *uWaveform, |
| int triggerCell, float threshold, bool offsetCalib); |
| bool SubtractADCOffset(unsigned int chipIndex, unsigned int channel, unsigned short *adcWaveform, |
| unsigned short *adcCalibratedWaveform, unsigned short newBaseLevel); |
| bool IsRead(int chipIndex) const { return fCalibrationValid[chipIndex]; } |
| double GetPrecision() const { return fPrecision; }; |
| double GetOffsetAt(int chip,int chn,int bin) const { return fCalibrationData[chip]->fChannel[chn]->fOffset[bin]; }; |
| double GetGainAt(int chip,int chn,int bin) const { return fCalibrationData[chip]->fChannel[chn]->fGain[bin]; }; |
| double GetMeasPointXAt(int ip) const { return fXXSave[ip]; }; |
| double GetMeasPointYAt(int ip) const { return fYYSave[ip]; }; |
| protected: |
| void InitFields(int numberOfPointsLowVolt, int numberOfPoints, int numberOfMode2Bins, int numberOfSamples, |
| int numberOfGridPoints, int numberOfXConstPoints, int numberOfXConstGridPoints, |
| double triggerFrequency, int showStatistics); |
| void DeleteFields(); |
| void CalibrationTrigger(int mode, double voltage); |
| void CalibrationStart(double voltage); |
| static float GetValue(float *coefficients, float u, int n); |
| static int Approx(float *p, float *uu, int np, int nu, float *coef); |
| static void LeastSquaresAccumulation(float **matrix, int nb, int *ip, int *ir, int mt, int jt); |
| static int LeastSquaresSolving(float **matrix, int nb, int ip, int ir, float *x, int n); |
| static void Housholder(int lpivot, int l1, int m, float **u, int iU1, int iU2, float *up, float **c, int iC1, |
| int iC2, int ice, int ncv); |
| static int MakeDir(const char *path); |
| static void Average(int method,float *samples,int numberOfSamples,float &mean,float &error,float sigmaBoundary); |
| }; |
| class DRSBoard { |
| protected: |
| class TimeData { |
| public: |
| class FrequencyData { |
| public: |
| int fFrequency; |
| double fBin[kNumberOfBins]; |
| }; |
| enum { |
| kMaxNumberOfFrequencies = 4000 |
| }; |
| int fChip; |
| int fNumberOfFrequencies; |
| FrequencyData *fFrequency[kMaxNumberOfFrequencies]; |
| private: |
| TimeData(const TimeData &c); // not implemented |
| TimeData &operator=(const TimeData &rhs); // not implemented |
| public: |
| TimeData() |
| :fChip(0) |
| ,fNumberOfFrequencies(0) { |
| } |
| ~TimeData() { |
| int i; |
| for (i = 0; i < fNumberOfFrequencies; i++) { |
| delete fFrequency[i]; |
| } |
| } |
| }; |
| public: |
| // DAC channels (CMC Version 1 : DAC_COFSA,DAC_COFSB,DAC_DRA,DAC_DSA,DAC_TLEVEL,DAC_ACALIB,DAC_DSB,DAC_DRB) |
| unsigned int fDAC_COFSA; |
| unsigned int fDAC_COFSB; |
| unsigned int fDAC_DRA; |
| unsigned int fDAC_DSA; |
| unsigned int fDAC_TLEVEL; |
| unsigned int fDAC_ACALIB; |
| unsigned int fDAC_DSB; |
| unsigned int fDAC_DRB; |
| // DAC channels (CMC Version 2+3 : DAC_COFS,DAC_DSA,DAC_DSB,DAC_TLEVEL,DAC_ADCOFS,DAC_CLKOFS,DAC_ACALIB) |
| unsigned int fDAC_COFS; |
| unsigned int fDAC_ADCOFS; |
| unsigned int fDAC_CLKOFS; |
| // DAC channels (CMC Version 4 : DAC_ROFS_1,DAC_DSA,DAC_DSB,DAC_ROFS_2,DAC_ADCOFS,DAC_ACALIB,DAC_INOFS,DAC_BIAS) |
| unsigned int fDAC_ROFS_1; |
| unsigned int fDAC_ROFS_2; |
| unsigned int fDAC_INOFS; |
| unsigned int fDAC_BIAS; |
| // DAC channels (USB EVAL1 (fBoardType 5) : DAC_ROFS_1,DAC_CMOFS,DAC_CALN,DAC_CALP,DAC_BIAS,DAC_TLEVEL,DAC_ONOFS) |
| // DAC channels (USB EVAL3 (fBoardType 7) : DAC_ROFS_1,DAC_CMOFS,DAC_CALN,DAC_CALP,DAC_BIAS,DAC_TLEVEL,DAC_ONOFS) |
| unsigned int fDAC_CMOFS; |
| unsigned int fDAC_CALN; |
| unsigned int fDAC_CALP; |
| unsigned int fDAC_ONOFS; |
| // DAC channels (DRS4 MEZZ1 (fBoardType 6) : DAC_ONOFS,DAC_CMOFSP,DAC_CALN,DAC_CALP,DAC_BIAS,DAC_CMOFSN,DAC_ROFS_1) |
| unsigned int fDAC_CMOFSP; |
| unsigned int fDAC_CMOFSN; |
| // DAC channels (DRS4 EVAL4 (fBoardType 8) : DAC_ONOFS,DAC_TLEVEL4,DAC_CALN,DAC_CALP,DAC_BIAS,DAC_TLEVEL1,DAC_TLEVEL2,DAC_TLEVEL3) |
| unsigned int fDAC_TLEVEL1; |
| unsigned int fDAC_TLEVEL2; |
| unsigned int fDAC_TLEVEL3; |
| unsigned int fDAC_TLEVEL4; |
| protected: |
| // Fields for DRS |
| int fDRSType; |
| int fBoardType; |
| int fNumberOfChips; |
| int fNumberOfChannels; |
| int fRequiredFirmwareVersion; |
| int fFirmwareVersion; |
| int fBoardSerialNumber; |
| int fHasMultiBuffer; |
| unsigned int fTransport; |
| unsigned int fCtrlBits; |
| int fNumberOfReadoutChannels; |
| int fReadoutChannelConfig; |
| int fADCClkPhase; |
| bool fADCClkInvert; |
| double fExternalClockFrequency; |
| #ifdef HAVE_USB |
| MUSB_INTERFACE *fUsbInterface; |
| #endif |
| #ifdef HAVE_VME |
| MVME_INTERFACE *fVmeInterface; |
| mvme_addr_t fBaseAddress; |
| #endif |
| int fSlotNumber; |
| double fNominalFrequency; |
| double fTrueFrequency; |
| double fTCALFrequency; |
| double fRefClock; |
| int fMultiBuffer; |
| int fDominoMode; |
| int fDominoActive; |
| int fADCActive; |
| int fChannelConfig; |
| int fChannelCascading; |
| int fChannelDepth; |
| int fWSRLoop; |
| int fReadoutMode; |
| unsigned short fReadPointer; |
| int fNMultiBuffer; |
| int fTriggerEnable1; |
| int fTriggerEnable2; |
| int fTriggerSource; |
| int fTriggerDelay; |
| double fTriggerDelayNs; |
| int fSyncDelay; |
| int fDelayedStart; |
| int fTranspMode; |
| int fDecimation; |
| unsigned short fStopCell[4]; |
| unsigned char fStopWSR[4]; |
| unsigned short fTriggerBus; |
| double fROFS; |
| double fRange; |
| double fCommonMode; |
| int fAcalMode; |
| int fbkAcalMode; |
| double fAcalVolt; |
| double fbkAcalVolt; |
| int fTcalFreq; |
| int fbkTcalFreq; |
| int fTcalLevel; |
| int fbkTcalLevel; |
| int fTcalPhase; |
| int fTcalSource; |
| int fRefclk; |
| unsigned char fWaveforms[kNumberOfChipsMax * kNumberOfChannelsMax * 2 * kNumberOfBins]; |
| // Fields for Calibration |
| int fMaxChips; |
| char fCalibDirectory[1000]; |
| // Fields for Response Calibration old method |
| ResponseCalibration *fResponseCalibration; |
| // Fields for Calibration new method |
| bool fVoltageCalibrationValid; |
| double fCellCalibratedRange; |
| double fCellCalibratedTemperature; |
| unsigned short fCellOffset[kNumberOfChipsMax * kNumberOfChannelsMax][kNumberOfBins]; |
| unsigned short fCellOffset2[kNumberOfChipsMax * kNumberOfChannelsMax][kNumberOfBins]; |
| double fCellGain[kNumberOfChipsMax * kNumberOfChannelsMax][kNumberOfBins]; |
| double fTimingCalibratedFrequency; |
| double fCellDT[kNumberOfChipsMax][kNumberOfChannelsMax][kNumberOfBins]; |
| // Fields for Time Calibration |
| TimeData **fTimeData; |
| int fNumberOfTimeData; |
| // General debugging flag |
| int fDebug; |
| // Fields for wave transfer |
| bool fWaveTransferred[kNumberOfChipsMax * kNumberOfChannelsMax]; |
| // Waveform Rotation |
| int fTriggerStartBin; // Start Bin of the trigger |
| private: |
| DRSBoard(const DRSBoard &c); // not implemented |
| DRSBoard &operator=(const DRSBoard &rhs); // not implemented |
| public: |
| // Public Methods |
| #ifdef HAVE_USB |
| DRSBoard(MUSB_INTERFACE * musb_interface, int usb_slot); |
| #endif |
| #ifdef HAVE_VME |
| DRSBoard(MVME_INTERFACE * mvme_interface, mvme_addr_t base_address, int slot_number); |
| MVME_INTERFACE *GetVMEInterface() const { return fVmeInterface; }; |
| #endif |
| ~DRSBoard(); |
| int SetBoardSerialNumber(unsigned short serialNumber); |
| int GetBoardSerialNumber() const { return fBoardSerialNumber; } |
| int HasMultiBuffer() const { return fHasMultiBuffer; } |
| int GetFirmwareVersion() const { return fFirmwareVersion; } |
| int GetRequiredFirmwareVersion() const { return fRequiredFirmwareVersion; } |
| int GetDRSType() const { return fDRSType; } |
| int GetBoardType() const { return fBoardType; } |
| int GetNumberOfChips() const { return fNumberOfChips; } |
| // channel : Flash ADC index |
| // readout channel : VME readout index |
| // input : Input on board |
| int GetNumberOfChannels() const { return fNumberOfChannels; } |
| int GetChannelDepth() const { return fChannelDepth; } |
| int GetChannelCascading() const { return fChannelCascading; } |
| inline int GetNumberOfReadoutChannels() const; |
| inline int GetWaveformBufferSize() const; |
| inline int GetNumberOfInputs() const; |
| inline int GetNumberOfCalibInputs() const; |
| inline int GetClockChannel() const; |
| inline int GetTriggerChannel() const; |
| inline int GetClockInput() const { return Channel2Input(GetClockChannel()); } |
| inline int GetTriggerInput() const { return fDRSType < 4 ? Channel2Input(GetTriggerChannel()) : -1; } |
| inline int Channel2Input(int channel) const; |
| inline int Channel2ReadoutChannel(int channel) const; |
| inline int Input2Channel(int input, int ind = 0) const; |
| inline int Input2ReadoutChannel(int input, int ind = 0) const; |
| inline int ReadoutChannel2Channel(int readout) const; |
| inline int ReadoutChannel2Input(int readout) const; |
| inline bool IsCalibChannel(int ch) const; |
| inline bool IsCalibInput(int input) const; |
| int GetSlotNumber() const { return fSlotNumber; } |
| int InitFPGA(void); |
| int Write(int type, unsigned int addr, void *data, int size); |
| int Read(int type, void *data, unsigned int addr, int size); |
| int GetTransport() const { return fTransport; } |
| void RegisterTest(void); |
| int RAMTest(int flag); |
| int ChipTest(); |
| unsigned int GetCtrlReg(void); |
| unsigned short GetConfigReg(void); |
| unsigned int GetStatusReg(void); |
| void SetLED(int state); |
| int SetChannelConfig(int firstChannel, int lastChannel, int nConfigChannels); |
| void SetADCClkPhase(int phase, bool invert); |
| void SetWarmup(unsigned int ticks); |
| void SetCooldown(unsigned int ticks); |
| int GetReadoutChannelConfig() { return fReadoutChannelConfig; } |
| void SetNumberOfChannels(int nChannels); |
| int EnableTrigger(int flag1, int flag2); |
| int GetTriggerEnable(int i) { return i?fTriggerEnable2:fTriggerEnable1; } |
| int SetDelayedTrigger(int flag); |
| int SetTriggerDelayPercent(int delay); |
| int SetTriggerDelayNs(int delay); |
| int GetTriggerDelay() { return fTriggerDelay; } |
| double GetTriggerDelayNs() { return fTriggerDelayNs; } |
| int SetSyncDelay(int ticks); |
| int SetTriggerLevel(double value); |
| int SetIndividualTriggerLevel(int channel, double voltage); |
| int SetTriggerPolarity(bool negative); |
| int SetTriggerSource(int source); |
| int GetTriggerSource() { return fTriggerSource; } |
| int SetDelayedStart(int flag); |
| int SetTranspMode(int flag); |
| int SetStandbyMode(int flag); |
| int SetDecimation(int flag); |
| int GetDecimation() { return fDecimation; } |
| int IsBusy(void); |
| int IsEventAvailable(void); |
| int IsPLLLocked(void); |
| int IsLMKLocked(void); |
| int IsNewFreq(unsigned char chipIndex); |
| int SetDAC(unsigned char channel, double value); |
| int ReadDAC(unsigned char channel, double *value); |
| int GetRegulationDAC(double *value); |
| int StartDomino(); |
| int StartClearCycle(); |
| int FinishClearCycle(); |
| int Reinit(); |
| int Init(); |
| void SetDebug(int debug) { fDebug = debug; } |
| int Debug() { return fDebug; } |
| int SetDominoMode(unsigned char mode); |
| int SetDominoActive(unsigned char mode); |
| int SetReadoutMode(unsigned char mode); |
| int SoftTrigger(void); |
| int ReadFrequency(unsigned char chipIndex, double *f); |
| int SetFrequency(double freq, bool wait); |
| double VoltToFreq(double volt); |
| double FreqToVolt(double freq); |
| double GetNominalFrequency() const { return fNominalFrequency; } |
| double GetTrueFrequency(); |
| int RegulateFrequency(double freq); |
| int SetExternalClockFrequency(double frequencyMHz); |
| double GetExternalClockFrequency(); |
| int SetMultiBuffer(int flag); |
| int IsMultiBuffer() { return fMultiBuffer; } |
| void ResetMultiBuffer(void); |
| int GetMultiBufferRP(void); |
| int SetMultiBufferRP(unsigned short rp); |
| int GetMultiBufferWP(void); |
| void IncrementMultiBufferRP(void); |
| void SetVoltageOffset(double offset1, double offset2); |
| int SetInputRange(double center); |
| double GetInputRange(void) { return fRange; } |
| double GetCalibratedInputRange(void) { return fCellCalibratedRange; } |
| double GetCalibratedTemperature(void) { return fCellCalibratedTemperature; } |
| double GetCalibratedFrequency(void) { return fTimingCalibratedFrequency; } |
| int TransferWaves(int numberOfChannels = kNumberOfChipsMax * kNumberOfChannelsMax); |
| int TransferWaves(unsigned char *p, int numberOfChannels = kNumberOfChipsMax * kNumberOfChannelsMax); |
| int TransferWaves(int firstChannel, int lastChannel); |
| int TransferWaves(unsigned char *p, int firstChannel, int lastChannel); |
| int DecodeWave(unsigned char *waveforms, unsigned int chipIndex, unsigned char channel, |
| unsigned short *waveform); |
| int DecodeWave(unsigned int chipIndex, unsigned char channel, unsigned short *waveform); |
| int GetWave(unsigned char *waveforms, unsigned int chipIndex, unsigned char channel, short *waveform, |
| bool responseCalib = false, int triggerCell = -1, int wsr = -1, bool adjustToClock = false, |
| float threshold = 0, bool offsetCalib = true); |
| int GetWave(unsigned char *waveforms, unsigned int chipIndex, unsigned char channel, float *waveform, |
| bool responseCalib = false, int triggerCell = -1, int wsr = -1, bool adjustToClock = false, |
| float threshold = 0, bool offsetCalib = true); |
| int GetWave(unsigned int chipIndex, unsigned char channel, short *waveform, bool responseCalib = false, |
| int triggerCell = -1, int wsr = -1, bool adjustToClock = false, float threshold = 0, bool offsetCalib = true); |
| int GetWave(unsigned int chipIndex, unsigned char channel, float *waveform, bool responseCalib, |
| int triggerCell = -1, int wsr = -1, bool adjustToClock = false, float threshold = 0, bool offsetCalib = true); |
| int GetWave(unsigned int chipIndex, unsigned char channel, float *waveform); |
| int GetRawWave(unsigned int chipIndex, unsigned char channel, unsigned short *waveform, bool adjustToClock = false); |
| int GetRawWave(unsigned char *waveforms,unsigned int chipIndex, unsigned char channel, |
| unsigned short *waveform, bool adjustToClock = false); |
| bool IsTimingCalibrationValid(void); |
| bool IsVoltageCalibrationValid(void) { return fVoltageCalibrationValid; } |
| int GetTime(unsigned int chipIndex, int channelIndex, double freq, int tc, float *time, bool tcalibrated=true, bool rotated=true); |
| int GetTime(unsigned int chipIndex, int channelIndex, int tc, float *time, bool tcalibrated=true, bool rotated=true); |
| int GetTimeCalibration(unsigned int chipIndex, int channelIndex, int mode, float *time, bool force=false); |
| int GetTriggerCell(unsigned int chipIndex); |
| int GetStopCell(unsigned int chipIndex); |
| unsigned char GetStopWSR(unsigned int chipIndex); |
| int GetTriggerCell(unsigned char *waveforms,unsigned int chipIndex); |
| void TestDAC(int channel); |
| void MeasureSpeed(); |
| void InteractSpeed(); |
| void MonitorFrequency(); |
| int TestShift(int n); |
| int EnableAcal(int mode, double voltage); |
| int GetAcalMode() { return fAcalMode; } |
| double GetAcalVolt() { return fAcalVolt; } |
| int EnableTcal(int freq, int level=0, int phase=0); |
| int SelectClockSource(int source); |
| int SetRefclk(int source); |
| int GetRefclk() { return fRefclk; } |
| int GetTcalFreq() { return fTcalFreq; } |
| int GetTcalLevel() { return fTcalLevel; } |
| int GetTcalPhase() { return fTcalPhase; } |
| int GetTcalSource() { return fTcalSource; } |
| int SetCalibVoltage(double value); |
| int SetCalibTiming(int t1, int t2); |
| double GetTemperature(); |
| int Is2048ModeCapable(); |
| int GetTriggerBus(); |
| unsigned int GetScaler(int channel); |
| int ReadEEPROM(unsigned short page, void *buffer, int size); |
| int WriteEEPROM(unsigned short page, void *buffer, int size); |
| bool HasCorrectFirmware(); |
| int ConfigureLMK(double sampFreq, bool freqChange, int calFreq, int calPhase); |
| bool InitTimeCalibration(unsigned int chipIndex); |
| void SetCalibrationDirectory(const char *calibrationDirectoryPath); |
| void GetCalibrationDirectory(char *calibrationDirectoryPath); |
| ResponseCalibration *GetResponseCalibration() const { return fResponseCalibration; } |
| double GetPrecision() const { return fResponseCalibration ? fResponseCalibration->GetPrecision() : 0.1; } |
| int CalibrateWaveform(unsigned int chipIndex, unsigned char channel, unsigned short *adcWaveform, |
| short *waveform, bool responseCalib, int triggerCell, bool adjustToClock, |
| float threshold, bool offsetCalib); |
| static void LinearRegression(double *x, double *y, int n, double *a, double *b); |
| void ReadSingleWaveform(int nChips, int nChan, |
| unsigned short wfu[kNumberOfChipsMax][kNumberOfChannelsMax][kNumberOfBins], bool rotated); |
| int AverageWaveforms(DRSCallback *pcb, int chipIndex, int nChan, int prog1, int prog2, unsigned short *awf, int n, bool rotated); |
| int RobustAverageWaveforms(DRSCallback *pcb, int chipIndex, int nChan, int prog1, int prog2, unsigned short *awf, int n, bool rotated); |
| int CalibrateVolt(DRSCallback *pcb); |
| int AnalyzePeriod(Averager *ave, int iIter, int nIter, int channel, float wf[kNumberOfBins], int tCell, double cellDV[kNumberOfBins], double cellDT[kNumberOfBins]); |
| int AnalyzeSlope(Averager *ave, int iIter, int nIter, int channel, float wf[kNumberOfBins], int tCell, double cellDV[kNumberOfBins], double cellDT[kNumberOfBins]); |
| int CalibrateTiming(DRSCallback *pcb); |
| static void RemoveSymmetricSpikes(short **wf, int nwf, |
| short diffThreshold, int spikeWidth, |
| short maxPeakToPeak, short spikeVoltage, |
| int nTimeRegionThreshold); |
| protected: |
| // Protected Methods |
| void ConstructBoard(); |
| void ReadSerialNumber(); |
| void ReadCalibration(void); |
| TimeData *GetTimeCalibration(unsigned int chipIndex, bool reinit = false); |
| int GetStretchedTime(float *time, float *measurement, int numberOfMeasurements, float period); |
| }; |
| int DRSBoard::GetNumberOfReadoutChannels() const |
| { |
| return (fDRSType == 4 && fReadoutChannelConfig == 4) ? 5 : fNumberOfChannels; |
| } |
| int DRSBoard::GetWaveformBufferSize() const |
| { |
| int nbin=0; |
| if (fDRSType < 4) { |
| nbin = fNumberOfChips * fNumberOfChannels * kNumberOfBins; |
| } else { |
| if (fBoardType == 6) { |
| if (fDecimation) { |
| nbin = fNumberOfChips * (4 * kNumberOfBins + kNumberOfBins / 2); |
| } else { |
| nbin = fNumberOfChips * 5 * kNumberOfBins; |
| } |
| } else if (fBoardType == 7 || fBoardType == 8 || fBoardType == 9) |
| nbin = fNumberOfChips * fNumberOfChannels * kNumberOfBins; |
| } |
| return nbin * static_cast<int>(sizeof(short int)); |
| } |
| int DRSBoard::GetNumberOfInputs() const |
| { |
| // return number of input channels excluding clock and trigger channels. |
| if (fDRSType < 4) { |
| return fNumberOfChannels - 2; |
| } else { |
| return fNumberOfChannels / 2; |
| } |
| } |
| int DRSBoard::GetNumberOfCalibInputs() const |
| { |
| return (fDRSType < 4) ? 2 : 1; |
| } |
| int DRSBoard::GetClockChannel() const |
| { |
| return fDRSType < 4 ? 9 : 8; |
| } |
| int DRSBoard::GetTriggerChannel() const |
| { |
| return fDRSType < 4 ? 8 : -1; |
| } |
| int DRSBoard::Channel2Input(int channel) const |
| { |
| return (fDRSType < 4) ? channel : channel / 2; |
| } |
| int DRSBoard::Channel2ReadoutChannel(int channel) const |
| { |
| if (fDRSType < 4) { |
| return channel; |
| } else { |
| if (fReadoutChannelConfig == 4) { |
| return channel / 2; |
| } else { |
| return channel; |
| } |
| } |
| } |
| int DRSBoard::Input2Channel(int input, int ind) const |
| { |
| if (fChannelCascading == 1) { |
| return (fDRSType < 4) ? input : (input * 2 + ind); |
| } else { |
| if (input == 4) { // clock |
| return 8; |
| } else { |
| return input; |
| } |
| } |
| } |
| int DRSBoard::Input2ReadoutChannel(int input, int ind) const |
| { |
| if (fDRSType < 4) { |
| return input; |
| } else { |
| if (fReadoutChannelConfig == 4) { |
| return input; |
| } else { |
| return (input * 2 + ind); |
| } |
| } |
| } |
| int DRSBoard::ReadoutChannel2Channel(int readout) const |
| { |
| if (fDRSType < 4) { |
| return readout; |
| } else { |
| if (fReadoutChannelConfig == 4) { |
| return readout * 2; |
| } else { |
| return readout; |
| } |
| } |
| } |
| int DRSBoard::ReadoutChannel2Input(int readout) const |
| { |
| if (fDRSType < 4) { |
| return readout; |
| } else { |
| if (fReadoutChannelConfig == 4) { |
| return readout; |
| } else { |
| return readout / 2; |
| } |
| } |
| } |
| bool DRSBoard::IsCalibChannel(int ch) const |
| { |
| // return if it is clock or trigger channel |
| if (fDRSType < 4) |
| return ch == GetClockChannel() || ch == GetTriggerChannel(); |
| else |
| return ch == GetClockChannel(); |
| } |
| bool DRSBoard::IsCalibInput(int input) const |
| { |
| // return if it is clock or trigger channel |
| int ch = Input2Channel(input); |
| if (fDRSType < 4) |
| return ch == GetClockChannel() || ch == GetTriggerChannel(); |
| else |
| return ch == GetClockChannel(); |
| } |
| class DRS { |
| protected: |
| // constants |
| enum { |
| kMaxNumberOfBoards = 40 |
| }; |
| protected: |
| DRSBoard *fBoard[kMaxNumberOfBoards]; |
| int fNumberOfBoards; |
| char fError[256]; |
| #ifdef HAVE_VME |
| MVME_INTERFACE *fVmeInterface; |
| #endif |
| private: |
| DRS(const DRS &c); // not implemented |
| DRS &operator=(const DRS &rhs); // not implemented |
| public: |
| // Public Methods |
| DRS(); |
| ~DRS(); |
| DRSBoard *GetBoard(int i) { return fBoard[i]; } |
| void SetBoard(int i, DRSBoard *b); |
| DRSBoard **GetBoards() { return fBoard; } |
| int GetNumberOfBoards() const { return fNumberOfBoards; } |
| bool GetError(char *str, int size); |
| void SortBoards(); |
| #ifdef HAVE_VME |
| MVME_INTERFACE *GetVMEInterface() const { return fVmeInterface; }; |
| #endif |
| }; |
| #endif // DRS_H |
| /cvi/instr/drsctrl/drs4.c |
|---|
| 0,0 → 1,216 |
| #include <utility.h> |
| #include <ansi_c.h> |
| #include <cvirte.h> |
| #include <userint.h> |
| #include "drs4.h" |
| #include "drsread.h" |
| static int daq_on; |
| static int ph, plothandle; |
| static int tfID; |
| static int controlID; |
| #define MAX_THREADS 10 |
| static CmtThreadPoolHandle poolHandle = 0; |
| int main (int argc, char *argv[]) { |
| if (InitCVIRTE (0, argv, 0) == 0) |
| return -1; /* out of memory */ |
| if ((ph = LoadPanel (0, "drs4.uir", PANEL)) < 0) |
| return -1; |
| SetStdioPort (CVI_STDIO_WINDOW); |
| SetSleepPolicy(VAL_SLEEP_MORE); |
| CmtNewThreadPool (MAX_THREADS, &poolHandle); |
| DisplayPanel (ph); |
| RunUserInterface (); |
| DiscardPanel (ph); |
| CmtDiscardThreadPool (poolHandle); |
| return 0; |
| } |
| static void start_timer (double tout) { |
| SetCtrlAttribute (ph, PANEL_TIMER, ATTR_INTERVAL, tout); |
| SetCtrlAttribute (ph, PANEL_TIMER, ATTR_ENABLED, 1); |
| } |
| static void stop_timer ( void ) { |
| SetCtrlAttribute (ph, PANEL_TIMER, ATTR_ENABLED, 0); |
| DRSSetTimeout(); |
| } |
| void CVICALLBACK EndOfThread ( CmtThreadPoolHandle poolhandle, |
| CmtThreadFunctionID functionID, unsigned int event, |
| int value, void *callbackData ) { |
| daq_on=0; |
| //SetDimming(0); |
| printf("End of Thread \n"); |
| return ; |
| } |
| int CVICALLBACK daq(void *functionData) { |
| int neve; |
| char filename[0xff]; |
| char smask[0xff]; |
| unsigned long mask; |
| int frequency; |
| double trgdelay; |
| double trglevel; |
| int trgtype; |
| int trgchannel; |
| int trgpolarity; |
| int verbose; |
| double range; |
| GetCtrlVal(ph, PANEL_FILENAME, filename ); |
| GetCtrlVal(ph, PANEL_MASK, smask ); |
| mask = strtoul (smask,NULL,0); |
| GetCtrlVal(ph,PANEL_NEVE, &neve); |
| GetCtrlVal(ph,PANEL_FREQUENCY, &frequency); |
| GetCtrlVal(ph,PANEL_TRGDELAY, &trgdelay); |
| GetCtrlVal(ph,PANEL_TRGCHANNEL, &trgchannel); |
| GetCtrlVal(ph,PANEL_TRGTYPE, &trgtype); |
| GetCtrlVal(ph,PANEL_TRGLEVEL, &trglevel); |
| GetCtrlVal(ph,PANEL_TRGPOLARITY, &trgpolarity); |
| GetCtrlVal(ph,PANEL_RANGE, &range); |
| GetCtrlVal(ph,PANEL_DEBUG, &verbose); |
| printf("mask=0x%x\n",mask); |
| DRSSetMask( (unsigned char)( mask & 0xF ) ); |
| DRSSetFrequency( frequency ); |
| DRSSetTriggerPolarity(trgpolarity); |
| DRSSetTriggerLevel(trglevel); |
| DRSSetRange ( range ); |
| DRSSetTriggerType( trgtype ); |
| DRSSetTriggerChannel(trgchannel ); |
| FILE *fp=fopen(filename,"wb"); |
| static unsigned char *buffer; |
| int buffer_size = 0; |
| const int nBoards=1; |
| const int waveDepth=1024; |
| if (buffer_size == 0) { |
| buffer_size = 4 + nBoards * (4 + 4*(4+waveDepth*4)); |
| buffer_size += 24 + nBoards * (8 + 4*(4+waveDepth*2)); |
| buffer = (unsigned char *)malloc(buffer_size); |
| } |
| time_t t,told, tstart; |
| if (!DRSInit()){ |
| time(&tstart); |
| told=tstart; |
| int i=0; |
| for (i=0; i<neve; i++) { |
| start_timer(1);// 1 s timeout |
| int retval = DRSRead(0); |
| stop_timer(); |
| int nb = ( retval == 0 && fp ) ? DRSToBuffer( buffer , i ) : 0; |
| SetCtrlVal(ph,PANEL_CEVE,i); |
| if (retval) i--; |
| if (!daq_on) break; |
| time(&t); |
| if (t!=told ) { |
| printf("%d events in %2.2f min (%d s) %s",i+1, (double)(t-tstart)/60.,(t-tstart), ctime(&t)); |
| } |
| told=t; |
| // Save data |
| if (nb>0 && fp) fwrite(buffer, 1,nb ,fp); |
| // Plot Data |
| for (int k=0;k<4;k++){ |
| if (! (mask & ( 0x1<<k )) ) continue; |
| float *t=DRSGetTime(k); |
| float *x=DRSGetWave(k); |
| if (!k){ |
| if (plothandle) DeleteGraphPlot (ph, PANEL_GRAPH, plothandle, VAL_DELAYED_DRAW); |
| plothandle = PlotXY (ph, PANEL_GRAPH, t, x, 1024, VAL_FLOAT, VAL_FLOAT, VAL_THIN_LINE, VAL_NO_POINT, VAL_SOLID, 1, VAL_BLUE); |
| } |
| for (int i=0 ; i<1024 ; i++) { |
| if (verbose) printf("[%d] %d. x= %3.2f y=%3.2f\n", k, i, t[i], x[i] ); |
| //h[k]->Fill( t[i], x[i]*1e-3); |
| } |
| } |
| } |
| time(&t); |
| printf("%d events in %2.2f min (%d s) %s",i+1, (double)(t-tstart)/60.,t-tstart, ctime(&t)); |
| DRSEnd(); |
| } |
| if (fp) fclose(fp); |
| free(buffer); |
| return 0; |
| } |
| int CVICALLBACK StartCB (int panel, int control, int event, |
| void *callbackData, int eventData1, int eventData2) { |
| ThreadFunctionPtr mythread = NULL; |
| switch (event) { |
| case EVENT_COMMIT: |
| mythread = daq; |
| if (mythread!=NULL) { |
| printf("New Thread panel=%d button=%d\n", panel, control); |
| // SetDimming(1); |
| controlID= control; |
| daq_on=1; |
| CmtScheduleThreadPoolFunctionAdv (poolHandle, mythread, &controlID, |
| DEFAULT_THREAD_PRIORITY, |
| EndOfThread, |
| EVENT_TP_THREAD_FUNCTION_END, |
| NULL, RUN_IN_SCHEDULED_THREAD, |
| &tfID); |
| } |
| break; |
| } |
| return 0; |
| } |
| int CVICALLBACK StopCB (int panel, int control, int event, |
| void *callbackData, int eventData1, int eventData2) { |
| switch (event) { |
| case EVENT_COMMIT: |
| daq_on=0; |
| break; |
| } |
| return 0; |
| } |
| int CVICALLBACK ExitCB (int panel, int control, int event, |
| void *callbackData, int eventData1, int eventData2) { |
| switch (event) { |
| case EVENT_COMMIT: |
| QuitUserInterface (0); |
| break; |
| } |
| return 0; |
| } |
| /cvi/instr/drsctrl/drs4.cws |
|---|
| 0,0 → 1,232 |
| [Workspace Header] |
| Version = 1302 |
| Pathname = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drs4.cws" |
| CVI Dir = "/c/program files (x86)/national instruments/cvi2013" |
| CVI Shared Dir = "/C/Program Files (x86)/National Instruments/Shared/CVI" |
| CVI Pub Local Dir = "/C/ProgramData/National Instruments/CVI2013" |
| CVI Pub Global Dir = "/C/ProgramData/National Instruments/CVI" |
| IVI Standard Root Dir = "/C/Program Files (x86)/IVI Foundation/IVI" |
| IVI Standard Root 64-bit Dir = "/C/Program Files/IVI Foundation/IVI" |
| VXIplug&play Framework Dir = "/C/Program Files (x86)/IVI Foundation/VISA/winnt" |
| VXIplug&play Framework 64-bit Dir = "/C/Program Files/IVI Foundation/VISA/win64" |
| Number of Projects = 1 |
| Active Project = 1 |
| Project 0001 = "drs4.prj" |
| Drag Bar Left = 360 |
| Window Top = 277 |
| Window Left = 205 |
| Window Bottom = 1617 |
| Window Right = 2435 |
| Maximized = False |
| Maximized Children = True |
| Max32 Number Of Errors = 20 |
| Track Include File Dependencies = True |
| Prompt For Missing Includes = True |
| Stop On First Error File = False |
| Bring Up Err Win At Start = True |
| Bring Up Err Win For Errors = False |
| Save Changes Before Running = "Always" |
| Save Changes Before Compiling = "Always" |
| Hide Windows = False |
| Break At First Statement = False |
| Sort Type = "File Name" |
| Number of Opened Files = 8 |
| Window Confinement Region Enabled = True |
| MainColumnWidth = 343 |
| FileDateColumnWidth = 70 |
| FileSizeColumnWidth = 70 |
| [Project Header 0001] |
| Version = 1302 |
| Don't Update DistKit = False |
| Platform Code = 4 |
| Build Configuration = "Debug" |
| Warn User If Debugging Release = 1 |
| Batch Build Release = False |
| Batch Build Debug = False |
| [File 0001] |
| Path = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drs4.c" |
| File Type = "CSource" |
| Disk Date = 3566382302 |
| In Projects = "1," |
| Window Top = 522 |
| Window Left = 247 |
| Window Z-Order = 1 |
| Source Window State = "1,147,148,148,0,0,0,0,0,229,0,2,0,2,0,67,14,0,26,2,349,683,1,0," |
| [File 0002] |
| Path = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drs4.uir" |
| File Type = "User Interface Resource" |
| Disk Date = 3566382690 |
| In Projects = "1," |
| Window Top = 132 |
| Window Left = 49 |
| Window Height = 349 |
| Window Width = 811 |
| Window Z-Order = 2 |
| [File 0003] |
| Path = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drs4.h" |
| File Type = "Include" |
| Disk Date = 3566380515 |
| In Projects = "" |
| Window Top = 67 |
| Window Left = 16 |
| Window Z-Order = 6 |
| Source Window State = "1,0,0,0,0,0,0,0,0,96,0,0,0,0,0,25,0,0,0,0,349,811,1,0," |
| [File 0004] |
| Path = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drsread.h" |
| File Type = "Include" |
| Disk Date = 3566381442 |
| In Projects = "" |
| Window Top = 197 |
| Window Left = 82 |
| Window Z-Order = 5 |
| Source Window State = "1,0,0,0,0,0,0,0,0,96,0,0,0,0,0,25,0,0,31,70,349,811,1,0," |
| [File 0005] |
| Path = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drsread.c" |
| File Type = "CSource" |
| Disk Date = 3566381600 |
| In Projects = "" |
| Window Top = 262 |
| Window Left = 115 |
| Window Z-Order = 4 |
| Source Window State = "1,0,0,0,0,0,0,0,0,96,0,0,0,0,0,25,0,0,30,26,349,811,1,0," |
| [File 0006] |
| Path = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drsread.lib" |
| File Type = "Library" |
| Disk Date = 3566381587 |
| In Projects = "1," |
| [File 0007] |
| Path = "/c/Users/rok/Documents/rok/lab/praktikum/mioni/mioni.c" |
| File Type = "CSource" |
| Disk Date = 3564730349 |
| In Projects = "" |
| Window Top = 132 |
| Window Left = 49 |
| Window Z-Order = 8 |
| Source Window State = "1,26,26,26,0,25,25,0,3,96,0,0,0,0,0,25,0,0,26,0,349,811,1,0," |
| [File 0008] |
| Path = "/c/home/git/arich/daq/sa02_daq/cvi/sa02_CVI.c" |
| File Type = "CSource" |
| Disk Date = 3559701358 |
| In Projects = "" |
| Window Top = 197 |
| Window Left = 82 |
| Window Z-Order = 3 |
| Source Window State = "1,362,370,362,7,60,7,0,3,96,0,0,0,0,0,25,330,0,370,60,349,811,1,0," |
| [File 0009] |
| Path = "/c/home/git/arich/daq/sa02_daq/sa02lib.c" |
| File Type = "CSource" |
| Disk Date = 3559701358 |
| In Projects = "" |
| Window Top = 262 |
| Window Left = 115 |
| Window Z-Order = 7 |
| Source Window State = "1,240,240,240,1,21,21,0,3,96,0,0,0,0,0,25,213,0,240,1,349,811,1,0," |
| [Tab Order] |
| Tab 0001 = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drs4.uir" |
| Tab 0002 = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drs4.c" |
| Tab 0003 = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drsread.c" |
| Tab 0004 = "/c/Users/rok/Documents/rok/lab/praktikum/mioni/mioni.c" |
| Tab 0005 = "/c/home/git/arich/daq/sa02_daq/cvi/sa02_CVI.c" |
| Tab 0006 = "/c/home/git/arich/daq/sa02_daq/sa02lib.c" |
| Tab 0007 = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drs4.h" |
| Tab 0008 = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drsread.h" |
| [Default Build Config 0001 Debug] |
| Generate Browse Info = False |
| Enable Uninitialized Locals Runtime Warning = True |
| Batch Build = False |
| Profile = "Disabled" |
| Debugging Level = "Standard" |
| Execution Trace = "Disabled" |
| Command Line Args = "" |
| Working Directory = "" |
| Environment Options = "" |
| External Process Path = "" |
| [Default Build Config 0001 Release] |
| Generate Browse Info = False |
| Enable Uninitialized Locals Runtime Warning = True |
| Batch Build = False |
| Profile = "Disabled" |
| Debugging Level = "Standard" |
| Execution Trace = "Disabled" |
| Command Line Args = "" |
| Working Directory = "" |
| Environment Options = "" |
| External Process Path = "" |
| [Default Build Config 0001 Debug64] |
| Generate Browse Info = False |
| Enable Uninitialized Locals Runtime Warning = True |
| Batch Build = False |
| Profile = "Disabled" |
| Debugging Level = "Standard" |
| Execution Trace = "Disabled" |
| Command Line Args = "" |
| Working Directory = "" |
| Environment Options = "" |
| External Process Path = "" |
| [Default Build Config 0001 Release64] |
| Generate Browse Info = False |
| Enable Uninitialized Locals Runtime Warning = True |
| Batch Build = False |
| Profile = "Disabled" |
| Debugging Level = "Standard" |
| Execution Trace = "Disabled" |
| Command Line Args = "" |
| Working Directory = "" |
| Environment Options = "" |
| External Process Path = "" |
| [Build Dependencies 0001] |
| Number of Dependencies = 0 |
| [Build Options 0001] |
| Generate Browse Info = False |
| Enable Uninitialized Locals Runtime Warning = True |
| Execution Trace = "Disabled" |
| Profile = "Disabled" |
| Debugging Level = "Standard" |
| Break On Library Errors = True |
| Break On First Chance Exceptions = False |
| [Execution Target 0001] |
| Execution Target Address = "Local desktop computer" |
| Execution Target Port = 0 |
| Execution Target Type = 0 |
| [SCC Options 0001] |
| Use global settings = True |
| SCC Provider = "" |
| SCC Project = "" |
| Local Path = "" |
| Auxiliary Path = "" |
| Perform Same Action For .h File As For .uir File = "Ask" |
| Perform Same Action For .cds File As For .prj File = "Ask" |
| Username = "" |
| Comment = "" |
| Use Default Username = False |
| Use Default Comment = False |
| Suppress CVI Error Messages = False |
| Always show confirmation dialog = True |
| [DLL Debugging Support 0001] |
| External Process Path = "" |
| [Command Line Args 0001] |
| Command Line Args = "" |
| Working Directory = "" |
| Environment Options = "" |
| /cvi/instr/drsctrl/drs4.exe |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |
| /cvi/instr/drsctrl/drs4.h |
|---|
| 0,0 → 1,55 |
| /**************************************************************************/ |
| /* LabWindows/CVI User Interface Resource (UIR) Include File */ |
| /* */ |
| /* WARNING: Do not add to, delete from, or otherwise modify the contents */ |
| /* of this include file. */ |
| /**************************************************************************/ |
| #include <userint.h> |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| /* Panels and Controls: */ |
| #define PANEL 1 |
| #define PANEL_Exit 2 /* control type: command, callback function: ExitCB */ |
| #define PANEL_STOP 3 /* control type: command, callback function: StopCB */ |
| #define PANEL_START 4 /* control type: command, callback function: StartCB */ |
| #define PANEL_TRGTYPE 5 /* control type: numeric, callback function: (none) */ |
| #define PANEL_TRGLEVEL 6 /* control type: numeric, callback function: (none) */ |
| #define PANEL_TRGDELAY 7 /* control type: numeric, callback function: (none) */ |
| #define PANEL_RANGE 8 /* control type: numeric, callback function: (none) */ |
| #define PANEL_TRGCHANNEL 9 /* control type: numeric, callback function: (none) */ |
| #define PANEL_CEVE 10 /* control type: numeric, callback function: (none) */ |
| #define PANEL_NEVE 11 /* control type: numeric, callback function: (none) */ |
| #define PANEL_FREQUENCY 12 /* control type: numeric, callback function: (none) */ |
| #define PANEL_TRGPOLARITY 13 /* control type: binary, callback function: (none) */ |
| #define PANEL_MASK 14 /* control type: string, callback function: (none) */ |
| #define PANEL_FILENAME 15 /* control type: string, callback function: (none) */ |
| #define PANEL_GRAPH 16 /* control type: graph, callback function: (none) */ |
| #define PANEL_DEBUG 17 /* control type: radioButton, callback function: (none) */ |
| #define PANEL_TIMER 18 /* control type: timer, callback function: (none) */ |
| /* Control Arrays: */ |
| /* (no control arrays in the resource file) */ |
| /* Menu Bars, Menus, and Menu Items: */ |
| /* (no menu bars in the resource file) */ |
| /* Callback Prototypes: */ |
| int CVICALLBACK ExitCB(int panel, int control, int event, void *callbackData, int eventData1, int eventData2); |
| int CVICALLBACK StartCB(int panel, int control, int event, void *callbackData, int eventData1, int eventData2); |
| int CVICALLBACK StopCB(int panel, int control, int event, void *callbackData, int eventData1, int eventData2); |
| #ifdef __cplusplus |
| } |
| #endif |
| /cvi/instr/drsctrl/drs4.prj |
|---|
| 0,0 → 1,432 |
| [Project Header] |
| Version = 1302 |
| Pathname = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drs4.prj" |
| CVI Dir = "/c/program files (x86)/national instruments/cvi2013" |
| CVI Shared Dir = "/C/Program Files (x86)/National Instruments/Shared/CVI" |
| CVI Pub Local Dir = "/C/ProgramData/National Instruments/CVI2013" |
| CVI Pub Global Dir = "/C/ProgramData/National Instruments/CVI" |
| IVI Standard Root Dir = "/C/Program Files (x86)/IVI Foundation/IVI" |
| VXIplug&play Framework Dir = "/C/Program Files (x86)/IVI Foundation/VISA/winnt" |
| IVI Standard Root 64-bit Dir = "/C/Program Files/IVI Foundation/IVI" |
| VXIplug&play Framework 64-bit Dir = "/C/Program Files/IVI Foundation/VISA/win64" |
| Number of Files = 3 |
| Target Type = "Executable" |
| Flags = 2064 |
| Copied From Locked InstrDrv Directory = False |
| Copied from VXIPNP Directory = False |
| Locked InstrDrv Name = "" |
| Don't Display Deploy InstrDrv Dialog = False |
| [Folders] |
| Include Files Folder Not Added Yet = True |
| Instrument Files Folder Not Added Yet = True |
| Folder 0 = "User Interface Files" |
| FolderEx 0 = "User Interface Files" |
| Folder 1 = "Source Files" |
| FolderEx 1 = "Source Files" |
| Folder 2 = "Library Files" |
| FolderEx 2 = "Library Files" |
| [File 0001] |
| File Type = "User Interface Resource" |
| Res Id = 1 |
| Path Is Rel = True |
| Path Rel To = "Project" |
| Path Rel Path = "drs4.uir" |
| Path = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drs4.uir" |
| Exclude = False |
| Project Flags = 0 |
| Folder = "User Interface Files" |
| Folder Id = 0 |
| [File 0002] |
| File Type = "CSource" |
| Res Id = 2 |
| Path Is Rel = True |
| Path Rel To = "Project" |
| Path Rel Path = "drs4.c" |
| Path = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drs4.c" |
| Exclude = False |
| Compile Into Object File = False |
| Project Flags = 0 |
| Folder = "Source Files" |
| Folder Id = 1 |
| [File 0003] |
| File Type = "Library" |
| Res Id = 3 |
| Path Is Rel = True |
| Path Rel To = "Project" |
| Path Rel Path = "drsread.lib" |
| Path = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drsread.lib" |
| Exclude = False |
| Project Flags = 0 |
| Folder = "Library Files" |
| Folder Id = 2 |
| [Custom Build Configs] |
| Num Custom Build Configs = 0 |
| [Default Build Config Debug] |
| Config Name = "Debug" |
| Is 64-Bit = False |
| Is Release = False |
| Default Calling Convention = "cdecl" |
| Optimization Level = "Optimize for speed (level 2)" |
| Require Prototypes = True |
| Show Warning IDs in Build Output = False |
| Selected Warning Level = "None" |
| Warning List None = "4,9,84,105,106,107,108,109,110,111" |
| Warning List Common = "" |
| Warning List Extended = "" |
| Warning List All = "" |
| Warning Mode = 0 |
| Enable Unreferenced Identifiers Warning = False |
| Enable Pointer Mismatch Warning = False |
| Enable Unreachable Code Warning = False |
| Enable Assignment In Conditional Warning = False |
| Uninitialized Locals Compile Warning = "Aggressive" |
| Require Return Values = True |
| Enable C99 Extensions = False |
| Enable OpenMP Extensions = False |
| Stack Size = 250000 |
| Stack Reserve = 1048576 |
| Stack Commit = 4096 |
| Image Base Address = 4194304 |
| Image Base Address x64 = 4194304 |
| Compiler Defines = "/DWIN32_LEAN_AND_MEAN" |
| Sign = False |
| Sign Store = "" |
| Sign Certificate = "" |
| Sign Timestamp URL = "" |
| Sign URL = "" |
| Manifest Embed = False |
| Icon File Is Rel = False |
| Icon File = "" |
| Application Title = "" |
| Use IVI Subdirectories for Import Libraries = False |
| Use VXIPNP Subdirectories for Import Libraries = False |
| Use Dflt Import Lib Base Name = True |
| Where to Copy DLL = "Do not copy" |
| Custom Directory to Copy DLL Is Rel = False |
| Custom Directory to Copy DLL = "" |
| Generate Source Documentation = "None" |
| Runtime Support = "Full Runtime Support" |
| Runtime Binding = "Shared" |
| Embed Project .UIRs = False |
| Generate Map File = False |
| Embed Timestamp = True |
| Create Console Application = False |
| Using LoadExternalModule = False |
| DLL Exports = "Include File Symbols" |
| Register ActiveX Server = False |
| Numeric File Version = "1,0,0,0" |
| Numeric Prod Version = "1,0,0,0" |
| Comments = "" |
| Comments Ex = "" |
| Company Name = "" |
| Company Name Ex = "%company" |
| File Description = "drs4 (Debug x86)" |
| File Description Ex = "%application (%rel_dbg %arch)" |
| File Version = "1.0" |
| File Version Ex = "%f1.%f2" |
| Internal Name = "drs4" |
| Internal Name Ex = "%basename" |
| Legal Copyright = "Copyright © 2017" |
| Legal Copyright Ex = "Copyright © %company %Y" |
| Legal Trademarks = "" |
| Legal Trademarks Ex = "" |
| Original Filename = "drs4.exe" |
| Original Filename Ex = "%filename" |
| Private Build = "" |
| Private Build Ex = "" |
| Product Name = " drs4" |
| Product Name Ex = "%company %application" |
| Product Version = "1.0" |
| Product Version Ex = "%p1.%p2" |
| Special Build = "" |
| Special Build Ex = "" |
| Add Type Lib To DLL = False |
| Include Type Lib Help Links = False |
| TLB Help Style = "HLP" |
| Type Lib FP File Is Rel = False |
| Type Lib FP File = "" |
| [Default Build Config Release] |
| Config Name = "Release" |
| Is 64-Bit = False |
| Is Release = True |
| Default Calling Convention = "cdecl" |
| Optimization Level = "Optimize for speed (level 2)" |
| Require Prototypes = True |
| Show Warning IDs in Build Output = False |
| Selected Warning Level = "None" |
| Warning List None = "4,9,84,105,106,107,108,109,110,111" |
| Warning List Common = "" |
| Warning List Extended = "" |
| Warning List All = "" |
| Warning Mode = 0 |
| Enable Unreferenced Identifiers Warning = False |
| Enable Pointer Mismatch Warning = False |
| Enable Unreachable Code Warning = False |
| Enable Assignment In Conditional Warning = False |
| Uninitialized Locals Compile Warning = "Aggressive" |
| Require Return Values = True |
| Enable C99 Extensions = False |
| Enable OpenMP Extensions = False |
| Stack Size = 250000 |
| Stack Reserve = 1048576 |
| Stack Commit = 4096 |
| Image Base Address = 4194304 |
| Image Base Address x64 = 4194304 |
| Compiler Defines = "/DWIN32_LEAN_AND_MEAN" |
| Sign = False |
| Sign Store = "" |
| Sign Certificate = "" |
| Sign Timestamp URL = "" |
| Sign URL = "" |
| Manifest Embed = False |
| Icon File Is Rel = False |
| Icon File = "" |
| Application Title = "" |
| Use IVI Subdirectories for Import Libraries = False |
| Use VXIPNP Subdirectories for Import Libraries = False |
| Use Dflt Import Lib Base Name = True |
| Where to Copy DLL = "Do not copy" |
| Custom Directory to Copy DLL Is Rel = False |
| Custom Directory to Copy DLL = "" |
| Generate Source Documentation = "None" |
| Runtime Support = "Full Runtime Support" |
| Runtime Binding = "Shared" |
| Embed Project .UIRs = False |
| Generate Map File = False |
| Embed Timestamp = True |
| Create Console Application = False |
| Using LoadExternalModule = False |
| DLL Exports = "Include File Symbols" |
| Register ActiveX Server = False |
| Add Type Lib To DLL = False |
| Include Type Lib Help Links = False |
| TLB Help Style = "HLP" |
| Type Lib FP File Is Rel = False |
| Type Lib FP File = "" |
| [Default Build Config Debug64] |
| Config Name = "Debug64" |
| Is 64-Bit = True |
| Is Release = False |
| Default Calling Convention = "cdecl" |
| Optimization Level = "Optimize for speed (level 2)" |
| Require Prototypes = True |
| Show Warning IDs in Build Output = False |
| Selected Warning Level = "None" |
| Warning List None = "4,9,84,105,106,107,108,109,110,111" |
| Warning List Common = "" |
| Warning List Extended = "" |
| Warning List All = "" |
| Warning Mode = 0 |
| Enable Unreferenced Identifiers Warning = False |
| Enable Pointer Mismatch Warning = False |
| Enable Unreachable Code Warning = False |
| Enable Assignment In Conditional Warning = False |
| Uninitialized Locals Compile Warning = "Aggressive" |
| Require Return Values = True |
| Enable C99 Extensions = False |
| Enable OpenMP Extensions = False |
| Stack Size = 250000 |
| Stack Reserve = 1048576 |
| Stack Commit = 4096 |
| Image Base Address = 4194304 |
| Image Base Address x64 = 4194304 |
| Compiler Defines = "/DWIN32_LEAN_AND_MEAN" |
| Sign = False |
| Sign Store = "" |
| Sign Certificate = "" |
| Sign Timestamp URL = "" |
| Sign URL = "" |
| Manifest Embed = False |
| Icon File Is Rel = False |
| Icon File = "" |
| Application Title = "" |
| Use IVI Subdirectories for Import Libraries = False |
| Use VXIPNP Subdirectories for Import Libraries = False |
| Use Dflt Import Lib Base Name = True |
| Where to Copy DLL = "Do not copy" |
| Custom Directory to Copy DLL Is Rel = False |
| Custom Directory to Copy DLL = "" |
| Generate Source Documentation = "None" |
| Runtime Support = "Full Runtime Support" |
| Runtime Binding = "Shared" |
| Embed Project .UIRs = False |
| Generate Map File = False |
| Embed Timestamp = True |
| Create Console Application = False |
| Using LoadExternalModule = False |
| DLL Exports = "Include File Symbols" |
| Register ActiveX Server = False |
| Add Type Lib To DLL = False |
| Include Type Lib Help Links = False |
| TLB Help Style = "HLP" |
| Type Lib FP File Is Rel = False |
| Type Lib FP File = "" |
| [Default Build Config Release64] |
| Config Name = "Release64" |
| Is 64-Bit = True |
| Is Release = True |
| Default Calling Convention = "cdecl" |
| Optimization Level = "Optimize for speed (level 2)" |
| Require Prototypes = True |
| Show Warning IDs in Build Output = False |
| Selected Warning Level = "None" |
| Warning List None = "4,9,84,105,106,107,108,109,110,111" |
| Warning List Common = "" |
| Warning List Extended = "" |
| Warning List All = "" |
| Warning Mode = 0 |
| Enable Unreferenced Identifiers Warning = False |
| Enable Pointer Mismatch Warning = False |
| Enable Unreachable Code Warning = False |
| Enable Assignment In Conditional Warning = False |
| Uninitialized Locals Compile Warning = "Aggressive" |
| Require Return Values = True |
| Enable C99 Extensions = False |
| Enable OpenMP Extensions = False |
| Stack Size = 250000 |
| Stack Reserve = 1048576 |
| Stack Commit = 4096 |
| Image Base Address = 4194304 |
| Image Base Address x64 = 4194304 |
| Compiler Defines = "/DWIN32_LEAN_AND_MEAN" |
| Sign = False |
| Sign Store = "" |
| Sign Certificate = "" |
| Sign Timestamp URL = "" |
| Sign URL = "" |
| Manifest Embed = False |
| Icon File Is Rel = False |
| Icon File = "" |
| Application Title = "" |
| Use IVI Subdirectories for Import Libraries = False |
| Use VXIPNP Subdirectories for Import Libraries = False |
| Use Dflt Import Lib Base Name = True |
| Where to Copy DLL = "Do not copy" |
| Custom Directory to Copy DLL Is Rel = False |
| Custom Directory to Copy DLL = "" |
| Generate Source Documentation = "None" |
| Runtime Support = "Full Runtime Support" |
| Runtime Binding = "Shared" |
| Embed Project .UIRs = False |
| Generate Map File = False |
| Embed Timestamp = True |
| Create Console Application = False |
| Using LoadExternalModule = False |
| DLL Exports = "Include File Symbols" |
| Register ActiveX Server = False |
| Add Type Lib To DLL = False |
| Include Type Lib Help Links = False |
| TLB Help Style = "HLP" |
| Type Lib FP File Is Rel = False |
| Type Lib FP File = "" |
| [Compiler Options] |
| Default Calling Convention = "cdecl" |
| Require Prototypes = True |
| Require Return Values = True |
| Enable Pointer Mismatch Warning = False |
| Enable Unreachable Code Warning = False |
| Enable Unreferenced Identifiers Warning = False |
| Enable Assignment In Conditional Warning = False |
| O Option Compatible With 5.0 = False |
| Enable C99 Extensions = False |
| Uninitialized Locals Compile Warning = "Aggressive" |
| Precompile Prefix Header = False |
| Prefix Header File = "" |
| [Run Options] |
| Stack Size = 250000 |
| Stack Commit = 4096 |
| Image Base Address = 4194304 |
| Image Base Address x64 = 4194304 |
| [Compiler Defines] |
| Compiler Defines = "/DWIN32_LEAN_AND_MEAN" |
| [Create Executable] |
| Executable File_Debug Is Rel = True |
| Executable File_Debug Rel To = "Project" |
| Executable File_Debug Rel Path = "drs4.exe" |
| Executable File_Debug = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drs4.exe" |
| Executable File_Release Is Rel = True |
| Executable File_Release Rel To = "Project" |
| Executable File_Release Rel Path = "drs4.exe" |
| Executable File_Release = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drs4.exe" |
| Executable File_Debug64 Is Rel = True |
| Executable File_Debug64 Rel To = "Project" |
| Executable File_Debug64 Rel Path = "drs4.exe" |
| Executable File_Debug64 = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drs4.exe" |
| Executable File_Release64 Is Rel = True |
| Executable File_Release64 Rel To = "Project" |
| Executable File_Release64 Rel Path = "drs4.exe" |
| Executable File_Release64 = "/c/Users/rok/Documents/rok/lab/drs/drsctrl/drs4.exe" |
| Icon File Is Rel = False |
| Icon File = "" |
| Application Title = "" |
| DLL Exports = "Include File Symbols" |
| Use IVI Subdirectories for Import Libraries = False |
| Use VXIPNP Subdirectories for Import Libraries = False |
| Use Dflt Import Lib Base Name = True |
| Where to Copy DLL = "Do not copy" |
| Custom Directory to Copy DLL Is Rel = False |
| Custom Directory to Copy DLL = "" |
| Generate Source Documentation = "None" |
| Add Type Lib To DLL = False |
| Include Type Lib Help Links = False |
| TLB Help Style = "HLP" |
| Type Lib FP File Is Rel = False |
| Type Lib FP File = "" |
| Type Lib Guid = "" |
| Runtime Support = "Full Runtime Support" |
| Instrument Driver Support Only = False |
| Embed Project .UIRs = False |
| Generate Map File = False |
| [External Compiler Support] |
| UIR Callbacks File Option = 0 |
| Using LoadExternalModule = False |
| Create Project Symbols File = True |
| UIR Callbacks Obj File Is Rel = False |
| UIR Callbacks Obj File = "" |
| Project Symbols H File Is Rel = False |
| Project Symbols H File = "" |
| Project Symbols Obj File Is Rel = False |
| Project Symbols Obj File = "" |
| [ActiveX Server Options] |
| Specification File Is Rel = False |
| Specification File = "" |
| Source File Is Rel = False |
| Source File = "" |
| Include File Is Rel = False |
| Include File = "" |
| IDL File Is Rel = False |
| IDL File = "" |
| Register ActiveX Server = False |
| [Signing Info] |
| Sign = False |
| Sign Debug Build = False |
| Store = "" |
| Certificate = "" |
| Timestamp URL = "" |
| URL = "" |
| [Manifest Info] |
| Embed = False |
| [tpcSection] |
| tpcEnabled = 0 |
| tpcOverrideEnvironment = 0 |
| tpcEnabled x64 = 0 |
| tpcOverrideEnvironment x64 = 0 |
| /cvi/instr/drsctrl/drs4.uir |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |
| /cvi/instr/drsctrl/drscl.cpp |
|---|
| 0,0 → 1,1647 |
| /********************************************************************\ |
| Name: drscl.cpp |
| Created by: Stefan Ritt |
| Contents: Command line interface to DRS chip via USB and VME |
| $Id: drscl.cpp 21435 2014-07-30 13:02:31Z ritt $ |
| \********************************************************************/ |
| #include <math.h> |
| #ifdef _MSC_VER |
| #include <windows.h> |
| #include <conio.h> |
| #include <io.h> |
| #include <direct.h> |
| #define DIR_SEPARATOR '\\' |
| #elif defined(OS_LINUX) || defined(OS_DARWIN) |
| #define O_BINARY 0 |
| #include <unistd.h> |
| #include <ctype.h> |
| #include <sys/ioctl.h> |
| #include <errno.h> |
| #define DIR_SEPARATOR '/' |
| #endif |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <fcntl.h> |
| #include <time.h> |
| #include <sys/stat.h> |
| #include <assert.h> |
| #include "strlcpy.h" |
| #include "DRS.h" |
| #ifdef HAVE_VME |
| #include "ace.h" |
| #endif |
| const char *drscl_svn_revision = "$Id: drscl.cpp 21435 2014-07-30 13:02:31Z ritt $"; |
| void print_help(); |
| void clear_screen(); |
| int match(const char *str, const char *cmd); |
| void cmd_loop(); |
| #if defined(OS_LINUX) || defined(OS_DARWIN) |
| #define getch() getchar() |
| #define Sleep(x) usleep(x*1000) |
| #endif |
| #ifdef _MSC_VER |
| #include <conio.h> |
| #define drs_kbhit() kbhit() |
| #endif |
| void print_help() |
| { |
| puts("Available commands:\n"); |
| puts("active <0|1> Set domino active mode on (1) or off (0)"); |
| puts("board <i>|<i1> <i2>|all Address individual board/range/all boards"); |
| puts("calib [dir] Response Calibration. Use dir=\"area\" for MEG"); |
| puts("chn [n] Set number of channels: 8, 4, 2, 1"); |
| puts("ct Chip Test"); |
| puts("del <0|1> Switch delayed start on/off"); |
| puts("dir Show CF directory"); |
| puts("dmode <0|1> Set Domino mode 0=single, 1=cont."); |
| puts("et EEPROM test"); |
| puts("exit Exit program"); |
| puts("freq <ghz> [0|1] Set frequency of board [without/with] regulation"); |
| puts("info Show information about board"); |
| puts("init Initialize board"); |
| puts("led <0|1> Turn LED on (1) or off (0)"); |
| puts("lock [0|1] Display lock status [without/with] restart"); |
| puts("multi [0|1] Turn multi-buffer mode on/off"); |
| puts("offset <voltage> Set offset voltage"); |
| puts("phase <value> [0|1] Set ADC clock phase and inversion"); |
| puts("quit Exit program"); |
| puts("ram Test speed to FPGA RAM"); |
| puts("range <center> Change input range to <center>+=0.5V"); |
| puts("read <chn> [0|1] [file] Read waveform to [file], chn=0..19 [with] calibration"); |
| puts("refclk [0|1] Use FPGA ref. clk (0) or ext. P2 ref. clk (1)"); |
| puts("reg Register test"); |
| puts("serial <number> Set serial number of board"); |
| puts("scan Scan for boards"); |
| puts("standby <0|1> Turn standby mode on (1) or off (0)"); |
| puts("start Start domino wave"); |
| puts("stop Issue soft trigger"); |
| puts("tcout [file] [idx_offset] Print time calibration of DRS4, or write it onto [file]"); |
| puts("tcs <0|1> Timing calibration signal on (1) or off (0)"); |
| puts("tcalib [freq] Timing Calibration"); |
| puts("tlevel <voltage> Set trigger level in Volts"); |
| puts("trans <0|1> Set transparent mode on (1) or off (0)"); |
| puts("trig <0|1> Hardware trigger on (1) or off (0)"); |
| puts("upload <file> Upload ACE file to CF"); |
| puts("volt off|<voltage> Turn calibration voltage on/off"); |
| puts(""); |
| } |
| /*------------------------------------------------------------------*/ |
| void clear_screen() |
| { |
| #ifdef _MSC_VER |
| HANDLE hConsole; |
| COORD coordScreen = { 0, 0 }; /* here's where we'll home the cursor */ |
| BOOL bSuccess; |
| DWORD cCharsWritten; |
| CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ |
| DWORD dwConSize; /* number of character cells in the current buffer */ |
| hConsole = GetStdHandle(STD_OUTPUT_HANDLE); |
| /* get the number of character cells in the current buffer */ |
| bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi); |
| dwConSize = csbi.dwSize.X * csbi.dwSize.Y; |
| /* fill the entire screen with blanks */ |
| bSuccess = FillConsoleOutputCharacter(hConsole, (TCHAR) ' ', dwConSize, coordScreen, &cCharsWritten); |
| /* put the cursor at (0, 0) */ |
| bSuccess = SetConsoleCursorPosition(hConsole, coordScreen); |
| return; |
| #else |
| printf("\033[2J"); |
| #endif |
| } |
| /*------------------------------------------------------------------*/ |
| int match(const char *str, const char *cmd) |
| { |
| int i; |
| if (str[0] == '\r' || str[0] == '\n') |
| return 0; |
| for (i = 0; i < (int) strlen(str); i++) { |
| if (toupper(str[i]) != toupper(cmd[i]) && str[i] != '\r' && str[i] != '\n') |
| return 0; |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| class ProgressBar : public DRSCallback |
| { |
| public: |
| void Progress(int prog); |
| }; |
| void ProgressBar::Progress(int prog) |
| { |
| if (prog == 0) |
| printf("[--------------------------------------------------]\r"); |
| printf("["); |
| for (int i=0 ; i<prog/2 ; i++) |
| printf("="); |
| printf("\r"); |
| fflush(stdout); |
| } |
| /*------------------------------------------------------------------*/ |
| void cmd_loop() |
| { |
| int i, j, idx, i_start, i_end, nparam, calib, status, debug, cascading, |
| ext_refclk; |
| char str[256], dir[256], line[256], file_name[256], param[10][100], *pc; |
| double freq, triggerfreq, range; |
| FILE *f = NULL; |
| DRS *drs; |
| DRSBoard *b; |
| #ifdef HAVE_VME |
| ACE ace; |
| #endif |
| static char bar[] = {'\\', '|', '/', '-'}; |
| /* do initial scan */ |
| drs = new DRS(); |
| if (drs->GetError(str, sizeof(str))) |
| printf("%s", str); |
| for (i=0 ; i<drs->GetNumberOfBoards() ; i++) { |
| b = drs->GetBoard(i); |
| #ifdef HAVE_VME |
| if (b->GetTransport() != 1) |
| printf("Found DRS%d board %2d on USB, serial #%04d, firmware revision %5d\n", |
| b->GetDRSType(), i, b->GetBoardSerialNumber(), b->GetFirmwareVersion()); |
| #else |
| printf("Found DRS%d board %2d on USB, serial #%04d, firmware revision %5d\n", |
| b->GetDRSType(), i, b->GetBoardSerialNumber(), b->GetFirmwareVersion()); |
| #endif |
| } |
| if (drs->GetNumberOfBoards()) { |
| i_start = 0; |
| i_end = 1; |
| b = drs->GetBoard(0); |
| } |
| else { |
| printf("No DRS Boards found\n"); |
| i_start = i_end = 0; |
| b = NULL; |
| } |
| puts(""); |
| do { |
| /* print prompt */ |
| if (i_start == i_end-1) |
| printf("B%d> ", i_start); |
| else if (i_start == 0 && i_end == 0) |
| printf("> "); |
| else |
| printf("B%d-%d> ", i_start, i_end-1); |
| memset(line, 0, sizeof(line)); |
| fgets(line, sizeof(line), stdin); |
| /* strip \r\n */ |
| while (strpbrk(line,"\n\r")) |
| *strpbrk(line,"\n\r") = 0; |
| /* analyze line */ |
| nparam = 0; |
| pc = line; |
| while (*pc == ' ') |
| pc++; |
| memset(param, 0, sizeof(param)); |
| do { |
| if (*pc == '"') { |
| pc++; |
| for (i = 0; *pc && *pc != '"'; i++) |
| param[nparam][i] = *pc++; |
| if (*pc) |
| pc++; |
| } else if (*pc == '\'') { |
| pc++; |
| for (i = 0; *pc && *pc != '\''; i++) |
| param[nparam][i] = *pc++; |
| if (*pc) |
| pc++; |
| } else if (*pc == '`') { |
| pc++; |
| for (i = 0; *pc && *pc != '`'; i++) |
| param[nparam][i] = *pc++; |
| if (*pc) |
| pc++; |
| } else |
| for (i = 0; *pc && *pc != ' '; i++) |
| param[nparam][i] = *pc++; |
| param[nparam][i] = 0; |
| while (*pc == ' ' || *pc == '\r' || *pc == '\n') |
| pc++; |
| nparam++; |
| } while (*pc); |
| if (param[0][0] == 0) { |
| } |
| /* help ---------- */ |
| else if ((param[0][0] == 'h' && param[0][1] == 'e') || param[0][0] == '?') |
| print_help(); |
| /* scan ---------- */ |
| else if (match(param[0], "scan")) { |
| j = 0; |
| do { |
| delete drs; |
| drs = new DRS(); |
| for (i=0 ; i<drs->GetNumberOfBoards() ; i++) { |
| b = drs->GetBoard(i); |
| #ifdef HAVE_VME |
| if (b->GetTransport() != 1) |
| printf("Found DRS%d board %2d on USB, serial #%04d, firmware revision %5d\n", |
| b->GetDRSType(), i, b->GetBoardSerialNumber(), b->GetFirmwareVersion()); |
| #else |
| printf("Found DRS%d board %2d on USB, serial #%04d, firmware revision %5d\n", |
| b->GetDRSType(), i, b->GetBoardSerialNumber(), b->GetFirmwareVersion()); |
| #endif |
| } |
| if (drs_kbhit()) |
| break; |
| if (param[1][0] == 'r') { |
| printf("%c\r", bar[j]); |
| fflush(stdout); |
| j = (j+1) % 4; |
| Sleep(1000); |
| } |
| } while (param[1][0] == 'r'); |
| while (drs_kbhit()) |
| getch(); |
| if (drs->GetNumberOfBoards()) { |
| i_start = 0; |
| i_end = 1; |
| b = drs->GetBoard(0); |
| } else { |
| printf("No DRS Boards found\n"); |
| i_start = i_end = 0; |
| b = NULL; |
| } |
| } |
| /* address board ---------- */ |
| else if (match(param[0], "board")) { |
| if (param[1][0] == 'a') { |
| i_start = 0; |
| i_end = drs->GetNumberOfBoards(); |
| b = drs->GetBoard(0); |
| } else if (param[2][0] && atoi(param[2]) > 0 && atoi(param[2]) < drs->GetNumberOfBoards()) { |
| i_start = atoi(param[1]); |
| i_end = atoi(param[2]) + 1; |
| b = drs->GetBoard(i_start); |
| } else if (atoi(param[1]) >= 0 && atoi(param[1]) < drs->GetNumberOfBoards()) { |
| i_start = atoi(param[1]); |
| i_end = i_start + 1; |
| b = drs->GetBoard(i_start); |
| } else |
| printf("Board #%d does not exist\n", atoi(param[1])); |
| } |
| /* info ---------- */ |
| else if (match(param[0], "info")) { |
| for (idx=i_start ; idx<i_end ; idx++) { |
| b = drs->GetBoard(idx); |
| printf("==============================\n"); |
| printf("Mezz. Board index: %d\n", idx); |
| #ifdef HAVE_VME |
| if (b->GetTransport() == TR_VME) { |
| printf("Slot: %d", (b->GetSlotNumber() >> 1)+2); |
| if ((b->GetSlotNumber() & 1) == 0) |
| printf(" upper\n"); |
| else |
| printf(" lower\n"); |
| } |
| #endif |
| printf("DRS type: DRS%d\n", b->GetDRSType()); |
| printf("Board type: %d\n", b->GetBoardType()); |
| printf("Serial number: %04d\n", b->GetBoardSerialNumber()); |
| printf("Firmware revision: %d\n", b->GetFirmwareVersion()); |
| printf("Temperature: %1.1lf C\n", b->GetTemperature()); |
| if (b->GetDRSType() == 4) { |
| printf("Input range: %1.2lgV...%1.2lgV\n", |
| b->GetInputRange()-0.5, b->GetInputRange()+0.5); |
| printf("Calibrated range: %1.2lgV...%1.2lgV\n", b->GetCalibratedInputRange()-0.5, |
| b->GetCalibratedInputRange()+0.5); |
| printf("Calibrated frequency: %1.3lf GHz\n", b->GetCalibratedFrequency()); |
| if (b->GetTransport() == TR_VME) { |
| printf("Multi Buffer WP: %d\n", b->GetMultiBufferWP()); |
| printf("Multi Buffer RP: %d\n", b->GetMultiBufferRP()); |
| } |
| } |
| printf("Status reg.: %08X\n", b->GetStatusReg()); |
| if (b->GetStatusReg() & BIT_RUNNING) |
| puts(" Domino wave running"); |
| if (b->GetDRSType() == 4) { |
| if (b->GetBoardType() == 5) { |
| if (b->GetStatusReg() & BIT_PLL_LOCKED0) |
| puts(" PLL locked"); |
| } else if (b->GetBoardType() == 6) { |
| i = 0; |
| if (b->GetStatusReg() & BIT_PLL_LOCKED0) i++; |
| if (b->GetStatusReg() & BIT_PLL_LOCKED1) i++; |
| if (b->GetStatusReg() & BIT_PLL_LOCKED2) i++; |
| if (b->GetStatusReg() & BIT_PLL_LOCKED3) i++; |
| if (i == 4) |
| puts(" All PLLs locked"); |
| else if (i == 0) |
| puts(" No PLL locked"); |
| else |
| printf(" %d PLLs locked\n", i); |
| if (b->GetStatusReg() & BIT_LMK_LOCKED) |
| puts(" LMK PLL locked"); |
| } |
| } else { |
| if (b->GetStatusReg() & BIT_NEW_FREQ1) |
| puts(" New Freq1 ready"); |
| if (b->GetStatusReg() & BIT_NEW_FREQ2) |
| puts(" New Freq2 ready"); |
| } |
| printf("Control reg.: %08X\n", b->GetCtrlReg()); |
| if (b->GetCtrlReg() & BIT_MULTI_BUFFER) |
| puts(" Multi-buffering enabled"); |
| if (b->GetDRSType() == 4) { |
| if (b->GetConfigReg() & BIT_CONFIG_DMODE) |
| puts(" DMODE circular"); |
| else |
| puts(" DMODE single shot"); |
| } else { |
| if (b->GetCtrlReg() & BIT_DMODE) |
| puts(" DMODE circular"); |
| else |
| puts(" DMODE single shot"); |
| } |
| if (b->GetCtrlReg() & BIT_LED) |
| puts(" LED"); |
| if (b->GetCtrlReg() & BIT_TCAL_EN) |
| puts(" TCAL enabled"); |
| if (b->GetDRSType() == 4) { |
| if (b->GetCtrlReg() & BIT_TRANSP_MODE) |
| puts(" TRANSP_MODE enabled"); |
| } else { |
| if (b->GetCtrlReg() & BIT_FREQ_AUTO_ADJ) |
| puts(" FREQ_AUTO_ADJ enabled"); |
| } |
| if (b->GetCtrlReg() & BIT_ENABLE_TRIGGER1) |
| puts(" Hardware trigger enabled"); |
| if (b->GetDRSType() == 4) { |
| if (b->GetCtrlReg() & BIT_READOUT_MODE) |
| puts(" Readout from stop"); |
| if (b->GetCtrlReg() & BIT_ENABLE_TRIGGER2) |
| puts(" Internal trigger enabled"); |
| } else { |
| if (b->GetCtrlReg() & BIT_LONG_START_PULSE) |
| puts(" LONG_START_PULSE"); |
| } |
| if (b->GetCtrlReg() & BIT_DELAYED_START) |
| puts(" DELAYED_START"); |
| if (b->GetCtrlReg() & BIT_ACAL_EN) |
| puts(" ACAL enabled"); |
| if (b->GetDRSType() < 4) |
| if (b->GetCtrlReg() & BIT_TRIGGER_DELAYED) |
| puts(" DELAYED_TRIGGER selected"); |
| if (b->GetBoardType() != 5) |
| printf("Trigger bus: %08X\n", b->GetTriggerBus()); |
| if (b->GetDRSType() == 4) { |
| if (b->GetRefclk() == 1) { |
| if (b->IsPLLLocked() && b->IsLMKLocked()) { |
| b->ReadFrequency(0, &freq); |
| printf("Frequency: %1.3lf GHz\n", freq); |
| } else { |
| if (!b->IsPLLLocked()) |
| printf("Frequency: PLL not locked\n"); |
| else |
| printf("Frequency: LMK chip not locked\n"); |
| } |
| } else { |
| if (b->IsPLLLocked()) { |
| b->ReadFrequency(0, &freq); |
| printf("Frequency: %1.3lf GHz\n", freq); |
| } else { |
| printf("Frequency: PLL not locked\n"); |
| } |
| } |
| } else { |
| if (b->IsBusy()) { |
| b->ReadFrequency(0, &freq); |
| printf("Frequency0: %1.4lf GHz\n", freq); |
| b->ReadFrequency(1, &freq); |
| printf("Frequency1: %1.4lf GHz\n", freq); |
| } else |
| puts("Domino wave stopped"); |
| } |
| } |
| } |
| /* init ---------- */ |
| else if (match(param[0], "init")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| b->Init(); |
| } |
| } |
| /* set led ---------- */ |
| else if (match(param[0], "led")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| if (atoi(param[1])) |
| b->SetLED(1); |
| else |
| b->SetLED(0); |
| } |
| } |
| /* set multi buffer mode ---------- */ |
| else if (match(param[0], "multi")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| if (atoi(param[1])) |
| b->SetMultiBuffer(1); |
| else |
| b->SetMultiBuffer(0); |
| } |
| } |
| /* lock status ---------- */ |
| else if (match(param[0], "lock")) { |
| int slot, found, restart; |
| restart = atoi(param[1]); |
| // select external reference clock |
| for (i=0 ; i<drs->GetNumberOfBoards() ; i++) { |
| b = drs->GetBoard(i); |
| b->SetRefclk(1); |
| b->SetFrequency(b->GetNominalFrequency(), true); |
| } |
| // loop until keyboard hit |
| do { |
| clear_screen(); |
| printf(" 1 1 1 1 1 1 1 1 1 1 2 2\n"); |
| printf("2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\n\n"); |
| // upper slots |
| for (slot = 2 ; slot<22 ; slot++) { |
| found = 0; |
| for (i=0 ; i<drs->GetNumberOfBoards() ; i++) { |
| b = drs->GetBoard(i); |
| if ((b->GetSlotNumber() & 1) == 0 && (b->GetSlotNumber() >> 1)+2 == slot) { |
| found = 1; |
| if (b->IsLMKLocked()) |
| printf("O "); |
| else |
| printf("- "); |
| } |
| } |
| if (!found) |
| printf(" "); |
| } |
| printf("\n"); |
| // lower slots |
| for (slot = 2 ; slot<22 ; slot++) { |
| found = 0; |
| for (i=0 ; i<drs->GetNumberOfBoards() ; i++) { |
| b = drs->GetBoard(i); |
| if ((b->GetSlotNumber() & 1) == 1 && (b->GetSlotNumber() >> 1)+2 == slot) { |
| found = 1; |
| if (b->IsLMKLocked()) |
| printf("O "); |
| else |
| printf("- "); |
| } |
| } |
| if (!found) |
| printf(" "); |
| } |
| printf("\n"); |
| if (restart) { |
| for (i=0 ; i<drs->GetNumberOfBoards() ; i++) { |
| b = drs->GetBoard(i); |
| b->SetFrequency(b->GetNominalFrequency(), true); |
| } |
| } |
| Sleep(300); |
| } while (!drs_kbhit()); |
| puts(""); |
| while (drs_kbhit()) |
| getch(); |
| } |
| /* start domino wave ---------- */ |
| else if (match(param[0], "start")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| b->StartDomino(); |
| b->ReadFrequency(0, &freq); |
| for (j=0 ; j<10 ; j++) |
| if (b->GetDRSType() != 4 || b->IsPLLLocked()) |
| break; |
| if (j == 10) |
| printf("Domino wave started but PLL did not lock!\n"); |
| else |
| printf("Domino wave started at %1.3lf GHz\n", freq); |
| } |
| } |
| /* issue soft trigger ---------- */ |
| else if (match(param[0], "stop")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| b->SoftTrigger(); |
| } |
| } |
| /* set serial ---------- */ |
| else if (match(param[0], "serial")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| if (param[1][0] == 0) { |
| printf("Serial number: "); |
| fgets(str, sizeof(str), stdin); |
| } else |
| strlcpy(str, param[1], sizeof(str)); |
| if (!b->SetBoardSerialNumber(atoi(str))) |
| printf("Board EEPROM is write protected\n"); |
| else |
| printf("Serial number successfully changed\n"); |
| } |
| } |
| /* eeprom test ---------- */ |
| else if (match(param[0], "et")) { |
| unsigned short buf[16384]; |
| unsigned short rbuf[16384]; |
| int n_error; |
| do { |
| for (i=0 ; i<16384 ; i++) |
| buf[i] = rand(); |
| b->WriteEEPROM(1, buf, sizeof(buf)); |
| memset(rbuf, 0, sizeof(rbuf)); |
| b->Write(T_RAM, 0, rbuf, sizeof(rbuf)); |
| b->ReadEEPROM(1, rbuf, sizeof(rbuf)); |
| for (i=n_error=0 ; i<16384 ; i++) |
| if (buf[i] != rbuf[i]) { |
| printf("%04X %04X - %04X\n", i, buf[i], rbuf[i]); |
| n_error++; |
| } |
| printf("32 kb written, %d errors\n", n_error); |
| } while (!drs_kbhit()); |
| while (drs_kbhit()) |
| getch(); |
| } |
| /* set frequency ---------- */ |
| else if (match(param[0], "freq")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| if (param[1][0] == 0) { |
| printf("Frequency: "); |
| fgets(str, sizeof(str), stdin); |
| } else |
| strlcpy(str, param[1], sizeof(str)); |
| b->SetDebug(1); |
| if (param[2][0] && atoi(param[2])) |
| b->RegulateFrequency(atof(str)); |
| else |
| b->SetFrequency(atof(str), true); |
| } |
| } |
| /* set calibration voltage ---------- */ |
| else if (match(param[0], "volt")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| if (param[1][0] == 0) { |
| printf("Voltage or \"off\": "); |
| fgets(str, sizeof(str), stdin); |
| } else |
| strlcpy(str, param[1], sizeof(str)); |
| if (str[0] == 'o') { |
| b->EnableAcal(0, 0); |
| puts("Calibration voltage turned off"); |
| } else { |
| b->EnableAcal(1, atof(str)); |
| printf("Voltage set to %1.3lf Volt\n", atof(str)); |
| } |
| } |
| } |
| /* set channel configuration ---------- */ |
| else if (match(param[0], "chn")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| if (param[1][0] == 0) { |
| printf("Number of channels (8,4,2,1): "); |
| fgets(str, sizeof(str), stdin); |
| } else |
| strlcpy(str, param[1], sizeof(str)); |
| if (b->SetChannelConfig(0, 8, atoi(str))) |
| printf("DRS4 configured for %d channels\n", atoi(str)); |
| } |
| } |
| /* set trigger level ---------- */ |
| else if (match(param[0], "tlevel")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| if (param[1][0] == 0) { |
| printf("Voltage: "); |
| fgets(str, sizeof(str), stdin); |
| } else |
| strlcpy(str, param[1], sizeof(str)); |
| b->SetTriggerLevel(atof(str)); |
| printf("Trigger level set to %1.3lf Volt\n", atof(str)); |
| } |
| } |
| /* trigger on/off ---------- */ |
| else if (match(param[0], "trig")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| b->EnableTrigger(atoi(param[1]), 0); |
| if (atoi(param[1]) == 1) { |
| puts("Hardware fast trigger is on"); |
| } else if (atoi(param[1]) == 2) { |
| puts("Hardware slow trigger is on"); |
| } else { |
| puts("Hardware trigger is off"); |
| } |
| } |
| } |
| /* timing calibration signal on/off ---------- */ |
| else if (match(param[0], "tcs")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| b->EnableTcal(atoi(param[1]), 0, 0); |
| b->SelectClockSource(0); |
| if (atoi(param[1])) |
| puts("Timing calibration signal is on"); |
| else |
| puts("Timing calibration signal is off"); |
| } |
| } |
| /* timing calibration signal on/off ---------- */ |
| else if (match(param[0], "refclk")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| b->SetRefclk(atoi(param[1])); |
| // re-set frequency since LMK configuration needs to be changed |
| b->SetFrequency(b->GetNominalFrequency(), true); |
| if (atoi(param[1])) |
| puts("Refclock set to external through P2"); |
| else |
| puts("Refclock set to internal (FPGA)"); |
| } |
| } |
| /* domino mode 0/1 ---------- */ |
| else if (match(param[0], "dmode")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| if (atoi(param[1]) == 1) { |
| b->SetDominoMode(1); |
| puts("Domino mode switched to cyclic"); |
| } else { |
| b->SetDominoMode(0); |
| puts("Domino mode switched to single shot"); |
| } |
| } |
| } |
| /* active mode 0/1 ---------- */ |
| else if (match(param[0], "active")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| if (atoi(param[1]) == 1) { |
| b->SetDominoActive(1); |
| puts("Domino wave active during readout"); |
| } else { |
| b->SetDominoMode(0); |
| puts("Domino wave stopped during readout"); |
| } |
| } |
| } |
| /* delayed start on/off ---------- */ |
| else if (match(param[0], "del")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| if (b->GetDRSType() == 4) |
| puts("Delayed start not possible for DRS4"); |
| else { |
| if (atoi(param[1]) == 1) { |
| b->SetDelayedStart(1); |
| puts("Delayed start is on"); |
| } else { |
| b->SetDelayedStart(0); |
| puts("Delayed start is off"); |
| } |
| } |
| } |
| } |
| /* transparent mode on/off ---------- */ |
| else if (match(param[0], "trans")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| if (b->GetDRSType() != 4) |
| puts("Transparen mode only possible for DRS4"); |
| else { |
| if (atoi(param[1]) == 1) { |
| b->SetTranspMode(1); |
| puts("Transparent mode is on"); |
| } else { |
| b->SetTranspMode(0); |
| puts("Transparent mode is off"); |
| } |
| } |
| } |
| } |
| /* standby mode on/off ---------- */ |
| else if (match(param[0], "standby")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| if (b->GetDRSType() != 4) |
| puts("Standby mode only possible for DRS4"); |
| else { |
| if (atoi(param[1]) == 1) { |
| b->SetStandbyMode(1); |
| puts("Standby mode is on"); |
| } else { |
| b->SetStandbyMode(0); |
| puts("Standby mode is off"); |
| } |
| } |
| } |
| } |
| /* offset ---------- */ |
| else if (match(param[0], "offset")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| b->SetVoltageOffset(atof(param[1]), atof(param[2])); |
| } |
| } |
| /* phase ---------- */ |
| else if (match(param[0], "phase")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| b->SetADCClkPhase(atoi(param[1]), atoi(param[2]) > 0); |
| } |
| } |
| /* directory ---------- */ |
| else if (match(param[0], "dir")) { |
| #ifdef HAVE_VME |
| #ifdef CF_VIA_USB |
| { |
| if (param[2][0]) |
| i = atoi(param[2]); |
| else |
| i = 1; |
| printf("Physical drive %d:\n", i); |
| if (ace_init(NULL, i, &ace) != ACE_SUCCESS) { |
| printf("Cannot access ACE on physical drive %d\n", i); |
| } else { |
| #else |
| for (i=i_start ; i<i_end ; i++) { |
| /* do only once per VME board */ |
| if (i_end - i_start > 1 && (i % 2) == 1) |
| continue; |
| b = drs->GetBoard(i); |
| printf("VME slot %2d: ", (b->GetSlotNumber() >> 1) + 2); |
| if (ace_init(b->GetVMEInterface(), (b->GetSlotNumber() >> 1)+2, &ace) != ACE_SUCCESS) { |
| printf("Cannot access ACE in slot %d\n", (b->GetSlotNumber() >> 1)+2); |
| } else { |
| #endif |
| ace_dir(&ace); |
| } |
| } |
| #else |
| printf("No VME support compiled into drscl\n"); |
| #endif // HAVE_VME |
| } |
| /* upload ---------- */ |
| else if (match(param[0], "upload")) { |
| #ifdef HAVE_VME |
| #ifdef CF_VIA_USB |
| { |
| if (param[2][0]) |
| i = atoi(param[2]); |
| else |
| i = 1; |
| printf("Physical drive %d:\n", i); |
| if (ace_init(NULL, i, &ace) != ACE_SUCCESS) { |
| printf("Cannot access ACE on physical drive %d\n", i); |
| } else { |
| #else |
| /* use SVN file as default */ |
| if (param[1][0] == 0) { |
| #ifdef _MSC_VER |
| if (b->GetDRSType() == 4) |
| strcpy(str, "c:\\meg\\online\\VPC\\drs4\\2vp30\\cflash\\drs4\\rev0\\rev0.ace"); |
| else if (b->GetDRSType() == 3) |
| strcpy(str, "c:\\meg\\online\\VPC\\drs3\\2vp30\\cflash\\drs3\\rev0\\rev0.ace"); |
| else |
| strcpy(str, "c:\\meg\\online\\VPC\\drs2\\2vp30\\cflash\\drs2\\rev0\\rev0.ace"); |
| #else |
| if (b->GetDRSType() == 4) |
| strcpy(str, "/home/meg/meg/online/VPC/drs4/2vp30/cflash/drs4/rev0/rev0.ace"); |
| else if (b->GetDRSType() == 3) |
| strcpy(str, "/home/meg/meg/online/VPC/drs3/2vp30/cflash/drs3/rev0/rev0.ace"); |
| else |
| strcpy(str, "/home/meg/meg/online/VPC/drs2/2vp30/cflash/drs2/rev0/rev0.ace"); |
| #endif |
| printf("Enter filename or hit return for \n%s\n", str); |
| fgets(line, sizeof(line), stdin); |
| if (line[0] == '\r' || line[0] == '\n') |
| strcpy(file_name, str); |
| else |
| strcpy(file_name, line); |
| strcpy(param[1], str); |
| } else |
| strcpy(file_name, param[1]); |
| for (i=i_start ; i<i_end ; i++) { |
| /* do only once per VME board */ |
| if (i_end - i_start > 1 && (i % 2) == 1) |
| continue; |
| b = drs->GetBoard(i); |
| if (b->GetTransport() == TR_USB) { |
| printf("Cannot upload to USB board.\n"); |
| } else { |
| printf("VME slot %d:\n", (b->GetSlotNumber() >> 1)+2); |
| if (ace_init(b->GetVMEInterface(), (b->GetSlotNumber() >> 1)+2, &ace) != ACE_SUCCESS) { |
| printf("Cannot access ACE in slot %d\n", (b->GetSlotNumber() >> 1)+2); |
| } else { |
| #endif |
| status = ace_upload(&ace, file_name); |
| } |
| } |
| } |
| printf("\nPlease issue a power cycle to activate new firmware\n"); |
| #else |
| printf("No VME support compiled into drscl\n"); |
| #endif // HAVE_VME |
| } |
| /* download ---------- */ |
| else if (match(param[0], "download")) { |
| #ifdef HAVE_VME |
| b = drs->GetBoard(i_start); |
| if (b->GetTransport() == TR_USB) { |
| printf("Cannot upload to USB board.\n"); |
| } else { |
| printf("VME slot %d:\n", (b->GetSlotNumber() >> 1)+2); |
| if (ace_init(b->GetVMEInterface(), (b->GetSlotNumber() >> 1)+2, &ace) != ACE_SUCCESS) { |
| printf("Cannot access ACE in slot %d\n", (b->GetSlotNumber() >> 1)+2); |
| } else { |
| strcpy(str, "rev0.ace"); |
| if (param[1][0] == 0) { |
| printf("Enter filename or hit return for \n%s\n", str); |
| fgets(line, sizeof(line), stdin); |
| if (line[0] == '\r' || line[0] == '\n') |
| strcpy(file_name, str); |
| else |
| strcpy(file_name, line); |
| strcpy(param[1], str); |
| } else |
| strcpy(file_name, param[1]); |
| if (strchr(file_name, '\r')) |
| *strchr(file_name, '\r') = 0; |
| if (strchr(file_name, '\n')) |
| *strchr(file_name, '\n') = 0; |
| status = ace_download(&ace, file_name); |
| } |
| } |
| #else |
| printf("No VME support compiled into drscl\n"); |
| #endif // HAVE_VME |
| } |
| /* calibration ---------- */ |
| else if (match(param[0], "calib")) { |
| debug = strcmp(param[1], "debug") == 0 || strcmp(param[2], "debug") == 0 || strcmp(param[3], "debug") == 0; |
| if (param[1][0]) { |
| strlcpy(dir, param[1], sizeof(str)); |
| } else |
| getcwd(dir, sizeof(dir)); |
| while (dir[strlen(dir)-1] == '\n' || dir[strlen(dir)-1] == '\r') |
| dir[strlen(dir)-1] = 0; |
| b = drs->GetBoard(i_start); |
| printf("\n Enter calibration frequency [GHz]: "); |
| fgets(line, sizeof(line), stdin); |
| freq = atof(line); |
| if (b->GetDRSType() == 2) { |
| printf(" Enter the expected trigger frequency [Hz]: "); |
| fgets(line, sizeof(line), stdin); |
| triggerfreq = atof(line); |
| } else |
| triggerfreq = 0; |
| ext_refclk = 0; |
| if (b->GetBoardType() == 6) { |
| printf("Use [e]xternal or [i]nternal reference clock: "); |
| fgets(line, sizeof(line), stdin); |
| ext_refclk = line[0] == 'e'; |
| } |
| if (b->GetDRSType() == 4) { |
| printf(" Enter range [V]: "); |
| fgets(line, sizeof(line), stdin); |
| range = atof(line); |
| printf(" Enter mode [1]024 or [2]048 bin mode: "); |
| fgets(line, sizeof(line), stdin); |
| cascading = atoi(line); |
| } else { |
| range = 0; |
| cascading = 0; |
| } |
| if (b->GetDRSType() == 4) { |
| printf("\nPlease make sure that no input signal are present then hit any key\r"); |
| fflush(stdout); |
| while (!drs_kbhit()); |
| printf(" \r"); |
| while (drs_kbhit()) |
| getchar(); |
| } |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| if (b->GetTransport() == TR_VME) |
| printf("Creating Calibration of Board in VME slot %2d %s, serial #%04d\n", |
| (b->GetSlotNumber() >> 1)+2, ((b->GetSlotNumber() & 1) == 0) ? "upper" : "lower", |
| b->GetBoardSerialNumber()); |
| else |
| printf("Creating Calibration of Board on USB, serial #%04d\n", |
| b->GetBoardSerialNumber()); |
| if (b->GetDRSType() == 4) { |
| ProgressBar p; |
| if (b->GetTransport() == TR_VME) { |
| if (cascading == 2) |
| b->SetChannelConfig(7, 8, 4); // 7 means read all 9 channels per chip |
| else |
| b->SetChannelConfig(7, 8, 8); |
| } else { |
| if (cascading == 2) |
| b->SetChannelConfig(0, 8, 4); |
| else |
| b->SetChannelConfig(0, 8, 8); |
| } |
| b->SetRefclk(ext_refclk); |
| b->SetFrequency(freq, true); |
| b->SetInputRange(range); |
| b->CalibrateVolt(&p); |
| } else { |
| b->SetDebug(debug); |
| b->Init(); |
| b->SetFrequency(freq, true); |
| b->SoftTrigger(); |
| if (b->GetDRSType() == 3) |
| b->GetResponseCalibration()->SetCalibrationParameters(1,11,0,20,0,0,0,0,0); |
| else |
| b->GetResponseCalibration()->SetCalibrationParameters(1,36,110,20,19,40,15,triggerfreq,0); |
| if (!strcmp(dir,"lab")) |
| b->SetCalibrationDirectory("C:/experiment/calibrations"); |
| else if (!strcmp(dir,"area")) |
| b->SetCalibrationDirectory("/home/meg/meg/online/calibrations"); |
| else |
| b->SetCalibrationDirectory(dir); |
| for (j=0;j<2;j++) { |
| b->GetResponseCalibration()->ResetCalibration(); |
| while (!b->GetResponseCalibration()->RecordCalibrationPoints(j)) {} |
| while (!b->GetResponseCalibration()->FitCalibrationPoints(j)) {} |
| while (!b->GetResponseCalibration()->OffsetCalibration(j)) {} |
| if (!b->GetResponseCalibration()->WriteCalibration(j)) |
| break; |
| } |
| } |
| } |
| } |
| /* timing calibration ---------- */ |
| else if (match(param[0], "tcalib")) { |
| freq = 0; |
| if (param[1][0]) |
| freq = atof(param[1]); |
| if (freq == 0) { |
| printf("Enter calibration frequency [GHz]: "); |
| fgets(line, sizeof(line), stdin); |
| freq = atof(line); |
| } |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| if (b->GetDRSType() < 4) |
| printf("Timing calibration not possivle for DRS2 or DRS3\n"); |
| else if (b->GetFirmwareVersion() < 13279) |
| printf("Firmware revision 13279 or later required for timing calibration\n"); |
| else if (b->GetDRSType() == 4) { |
| printf("Creating Timing Calibration of Board #%d\n", b->GetBoardSerialNumber()); |
| ProgressBar p; |
| b->SetFrequency(freq, true); |
| status = b->CalibrateTiming(&p); |
| if (!status) |
| printf("Error performing timing calibration, please check waveforms\n"); |
| printf("\n"); |
| } |
| } |
| } |
| /* tcout ---------- */ |
| else if (match(param[0], "tcout")) { |
| float time[1024]; |
| int chip; |
| int k; |
| int idx = 0; |
| int first_board = i_start; |
| int last_board = i_end; |
| file_name[0] = 0; |
| strcpy(file_name, param[1]); |
| if (file_name[0]) { |
| f = fopen(file_name, "wt"); |
| if (f == NULL) { |
| printf("Cannot open file \"%s\"\n", file_name); |
| } else { |
| first_board = 0; |
| last_board = drs->GetNumberOfBoards(); |
| } |
| idx += atoi(param[2]); |
| } else |
| f = NULL; |
| if (f) { |
| fprintf(f, "-- Replace %%%% with correct id\n"); |
| } |
| for (i=first_board ; i<last_board ; i++) { |
| b = drs->GetBoard(i); |
| if (b->GetDRSType() >= 4) { |
| for (chip = 0; chip < b->GetNumberOfChips(); chip++) { |
| b->GetTime(chip, 0, b->GetTriggerCell(0), time, true, false); |
| if (f) { |
| fprintf(f, "INSERT INTO MEGDRSTimeCalibration VALUES(%%%%,%d,%d", idx, |
| static_cast<int>(b->GetNominalFrequency() * 10 + 0.5) * 100); |
| for (j=0 ; j<1024 ; j++) |
| fprintf(f, ",%g", time[j] * 1e-9); |
| fprintf(f, ",%d,%d", b->GetBoardSerialNumber(), chip); |
| fprintf(f, ",%g);\n", 1 / (b->GetNominalFrequency() * 1e9) * 1024); |
| idx++; |
| } else { |
| printf("Board %d\n", b->GetBoardSerialNumber()); |
| for (j=0 ; j<128 ; j++) { |
| printf("%4d: ", j*8); |
| for (k=0 ; k<7 ; k++) |
| printf("%6.1lf ", time[j*8+k]); |
| printf("%6.1lf\n", time[j*8+k]); |
| } |
| printf("n"); |
| } |
| } |
| } else { |
| // DRS2 or DRS3 |
| idx += 2; |
| } |
| } |
| if (f) { |
| fclose(f); |
| printf("Data successfully written to \"%s\"\n", file_name); |
| } |
| } |
| /* read */ |
| else if (match(param[0], "read")) { |
| float waveform[2048]; |
| short swaveform[2048]; |
| calib = 0; |
| file_name[0] = 0; |
| if (param[1][0]) { |
| idx = atoi(param[1]); |
| calib = atoi(param[2]); |
| if (strlen(param[2]) > 2) |
| strcpy(file_name, param[2]); |
| else |
| strcpy(file_name, param[3]); |
| } else { |
| printf("Enter channel number (0..19): "); |
| fgets(line, sizeof(line), stdin); |
| idx = atoi(line); |
| } |
| if (idx<0 || idx>19) |
| printf("Channel number must be between 0 and 19\n"); |
| else { |
| b = drs->GetBoard(i_start); |
| if (!b->IsEventAvailable()) |
| printf("Error: Domino wave is running, please issue a \"stop\" first\n"); |
| else { |
| if (calib == 1) { |
| if (b->GetDRSType() == 4) { |
| if (!b->IsVoltageCalibrationValid()) { |
| printf("Calibration not valid for board #%d\n", b->GetBoardSerialNumber()); |
| calib = 0; |
| } |
| } else { |
| #ifdef _MSC_VER |
| b->SetCalibrationDirectory("C:/experiment/calibrations"); |
| #else |
| b->SetCalibrationDirectory("/home/meg/meg/online/calibrations"); |
| #endif |
| if (!b->GetResponseCalibration()->IsRead(0)) |
| if (!b->GetResponseCalibration()->ReadCalibration(0)) |
| calib = 0; |
| if (!b->GetResponseCalibration()->IsRead(1)) |
| if (!b->GetResponseCalibration()->ReadCalibration(1)) |
| calib = 0; |
| } |
| } |
| status = b->TransferWaves(idx, idx); |
| if (file_name[0]) { |
| f = fopen(file_name, "wt"); |
| if (f == NULL) |
| printf("Cannot open file \"%s\"\n", file_name); |
| } else |
| f = NULL; |
| if (calib) { |
| status = b->GetWave(idx/b->GetNumberOfChannels(), idx%b->GetNumberOfChannels(), waveform, |
| true, b->GetTriggerCell(idx/b->GetNumberOfChannels()), b->GetStopWSR(idx/b->GetNumberOfChannels())); |
| if (status == 0) { |
| if (f) |
| for (i=0 ; i<b->GetChannelDepth() ; i++) |
| fprintf(f, "%6.1lf\n", waveform[i]); |
| else { |
| for (i=0 ; i<b->GetChannelDepth()/8 ; i++) { |
| printf("%4d: ", i*8); |
| for (j=0 ; j<7 ; j++) |
| printf("%6.1lf ", waveform[i*8+j]); |
| printf("%6.1lf\n", waveform[i*8+j]); |
| } |
| } |
| } |
| } else { |
| status = b->GetWave(idx/b->GetNumberOfChannels(), idx%b->GetNumberOfChannels(), swaveform, 0, 0); |
| if (status == 0) { |
| if (f) |
| for (i=0 ; i<b->GetChannelDepth() ; i++) |
| fprintf(f, "%4d\n", swaveform[i]); |
| else { |
| for (i=0 ; i<b->GetChannelDepth()/16 ; i++) { |
| for (j=0 ; j<15 ; j++) |
| printf("%4d ", swaveform[i*16+j] >> 4); |
| printf("%4d\n", swaveform[i*16+j] >> 4); |
| } |
| } |
| } |
| } |
| } |
| } |
| if (f) { |
| fclose(f); |
| printf("Data successfully written to \"%s\"\n", file_name); |
| } |
| } |
| /* register test ---------- */ |
| else if (match(param[0], "reg")) { |
| b->RegisterTest(); |
| } |
| /* RAM test */ |
| else if (match(param[0], "ram")) { |
| if (param[1][0] == 0) |
| b->RAMTest(3); |
| else |
| b->RAMTest(atoi(param[1])); |
| } |
| /* Change input range */ |
| else if (match(param[0], "range")) { |
| for (i=i_start ; i<i_end ; i++) { |
| b = drs->GetBoard(i); |
| if (param[1][0] == 0) { |
| printf("Input range: "); |
| fgets(str, sizeof(str), stdin); |
| } else |
| strlcpy(str, param[1], sizeof(str)); |
| b->SetInputRange(atof(str)); |
| printf("Range set to %1.2lg V ... %1.2lg V\n", atof(str)-0.5, atof(str)+0.5); |
| } |
| } |
| /* Chip Test */ |
| else if (match(param[0], "ct")) { |
| if (drs->GetNumberOfBoards() == 0) |
| puts("No DRS board found"); |
| else { |
| puts("Press 'q' to quit, any other key to repeat test.\n"); |
| do { |
| if (b->ChipTest()) |
| puts("Chip test successfully finished"); |
| else |
| puts("\007Chip Error!"); |
| b->SetStandbyMode(1); |
| for (i=0 ; i<8 ; i++) |
| b->SetDAC(i, 0); |
| i = getch(); |
| b->SetStandbyMode(0); |
| } while (i != 'q'); |
| } |
| } |
| /* calib0 for speed vs. temperature calibration */ |
| else if (match(param[0], "c0")) { |
| double volt, freq; |
| b->Init(); |
| b->SetFrequency(5, true); |
| b->EnableAcal(0, 0); |
| b->SetDominoMode(1); |
| for (volt=2.5 ; volt > 0 ; volt -= 0.05) { |
| printf("%4.1lf - %5.3lf ", b->GetTemperature(), volt); |
| b->SetDAC(1, volt); |
| b->SetDAC(2, volt); |
| Sleep(100); |
| b->ReadFrequency(0, &freq); |
| printf("%5.3lf\n", freq); |
| if (drs_kbhit()) |
| break; |
| } |
| while (drs_kbhit()) |
| getch(); |
| b->Init(); // reset voltage offset |
| } |
| /* calib1 */ |
| else if (match(param[0], "c1")) { |
| short swaveform[1024]; |
| double volt; |
| double av[1024]; |
| int k; |
| b->Init(); |
| b->SetFrequency(5, true); |
| b->SetDominoMode(1); |
| b->SetDominoActive(1); |
| b->SetReadoutMode(1); |
| for (volt=-0.5 ; volt <= 0.5001 ; volt += 0.02) { |
| printf("%4.1lf - %6.0lf ", b->GetTemperature(), 1000*volt); |
| b->EnableAcal(1, volt); |
| b->StartDomino(); |
| Sleep(100); |
| memset(av, 0, sizeof(av)); |
| for (j=0 ; j<100 ; j++) { |
| for (i=0 ; i<10 ; i++) |
| b->IsBusy(); |
| b->SoftTrigger(); |
| while (b->IsBusy()); |
| b->StartDomino(); |
| b->TransferWaves(b->GetNumberOfChannels()*b->GetNumberOfChips()); |
| i = b->GetTriggerCell(0); |
| b->GetWave(0, 0, swaveform, false, i, 1); |
| for (k=0 ; k<1024 ; k++) |
| av[k] += swaveform[k]; |
| if (drs_kbhit()) |
| break; |
| } |
| for (k=0 ; k<1024 ; k++) |
| av[k] /= j; |
| for (k=0 ; k<5 ; k++) |
| printf("%10.2lf ", 1000*(av[k]/65536-0.5)); |
| printf("\n"); |
| if (drs_kbhit()) |
| break; |
| } |
| // keep chip "warm" |
| b->StartDomino(); |
| } |
| /* test0 */ |
| else if (match(param[0], "t0")) { |
| b->Init(); |
| b->SetDominoMode(1); |
| b->SetDominoActive(1); |
| b->SetReadoutMode(1); |
| b->SetFrequency(0.8, true); |
| b->EnableTrigger(1, 0); |
| b->SetTriggerLevel(1); |
| b->SetChannelConfig(0, 8, 4); |
| do { |
| b->StartDomino(); |
| while (b->IsBusy()) |
| if (drs_kbhit()) |
| break; |
| b->TransferWaves(); |
| if (b->GetBoardType() == 5) { |
| printf("%04d(0x%03X) - %3d\n", b->GetTriggerCell(0), b->GetTriggerCell(0), |
| b->GetStopWSR(0)); |
| } else { |
| printf("%04d %04d %04d %04d - %3d %3d %3d\n", |
| b->GetTriggerCell(0), |
| b->GetTriggerCell(1), |
| b->GetTriggerCell(2), |
| b->GetTriggerCell(3), |
| b->GetTriggerCell(1)-b->GetTriggerCell(0), |
| b->GetTriggerCell(2)-b->GetTriggerCell(0), |
| b->GetTriggerCell(3)-b->GetTriggerCell(0)); |
| } |
| Sleep(300); |
| } while (!drs_kbhit()); |
| while (drs_kbhit()) |
| getch(); |
| } |
| /* test1 simple start/stop loop */ |
| else if (match(param[0], "t1")) { |
| time_t t1, t2; |
| b->SetDebug(1); |
| b->Init(); |
| b->SetFrequency(5, true); |
| b->SetDominoMode(1); |
| b->SetReadoutMode(0); |
| b->SetTranspMode(0); |
| b->SetDominoActive(1); |
| b->EnableAcal(1, 0.5); |
| b->EnableTcal(1); |
| time(&t1); |
| do { |
| time(&t2); |
| } while (t1 == t2); |
| i=0; |
| t1 = t2; |
| do { |
| b->StartDomino(); |
| b->SoftTrigger(); |
| b->TransferWaves(); |
| i++; |
| time(&t2); |
| if (t2 > t1) { |
| printf("%d events/sec\n", i); |
| i = 0; |
| t1 = t2; |
| } |
| } while (!drs_kbhit()); |
| while (drs_kbhit()) |
| getch(); |
| } |
| /* test2 readout from stop position */ |
| else if (match(param[0], "t2")) { |
| short sw[1024]; |
| double volt = 0.5; |
| b->Init(); |
| b->SetNumberOfChannels(10); |
| b->SetChannelConfig(0, 9, 12); |
| b->SetFrequency(2, true); |
| b->EnableTcal(1); |
| b->SetReadoutMode(0); |
| b->SetDominoActive(0); |
| b->SetDominoMode(1); |
| b->SetCalibTiming(0, 0); |
| b->StartDomino(); |
| b->EnableAcal(1, 0.5); |
| if (!b->GetResponseCalibration()->IsRead(0)) |
| if (!b->GetResponseCalibration()->ReadCalibration(0)) |
| printf("cannot read calibration\n"); |
| do { |
| //volt += 0.25; |
| if (volt > 1) |
| volt = 0; |
| b->SoftTrigger(); |
| while (b->IsBusy()); |
| b->StartDomino(); |
| b->EnableAcal(1, volt); |
| b->TransferWaves(); |
| b->GetWave(0, 1, sw, 0, 0); |
| printf("%d ", sw[100]); |
| b->GetWave(0, 1, sw, 1, 0); |
| printf("%1.4lf\n", sw[100]/4096.0); |
| } while (!drs_kbhit()); |
| while (drs_kbhit()) getch(); |
| } |
| /* DAC Loop */ |
| else if (match(param[0], "t3")) { |
| double volt; |
| do { |
| for (volt=2.5 ; volt > 0 ; volt -= 0.05) { |
| printf("%4.1lf - %5.3lf\n", b->GetTemperature(), volt); |
| b->SetDAC(0, volt); |
| b->SetDAC(1, 2.5-volt); |
| Sleep(100); |
| if (drs_kbhit()) |
| break; |
| } |
| } while (!drs_kbhit()); |
| while (drs_kbhit()) |
| getch(); |
| } |
| /* noise measurement */ |
| else if (match(param[0], "t4")) { |
| int i, n; |
| short sw[1024]; |
| double ofs[1024], sx, sxx, avg, stdev, enob; |
| b->Init(); |
| b->SetFrequency(2, true); |
| b->EnableTcal(0); |
| b->SetDominoMode(1); |
| b->StartDomino(); |
| b->EnableAcal(1, 0.5); |
| Sleep(100); |
| b->SoftTrigger(); |
| while (b->IsBusy()); |
| b->StartDomino(); |
| Sleep(100); |
| memset(ofs, 0, sizeof(ofs)); |
| for (i=0 ; i<10 ; i++) { |
| b->SoftTrigger(); |
| while (b->IsBusy()); |
| b->StartDomino(); |
| b->TransferWaves(1); |
| b->GetWave(0, 0, sw, 0, 0); |
| sx = sxx = 0; |
| for (n=0 ; n<1024 ; n++) { |
| ofs[n] += sw[n]; |
| } |
| } |
| for (n=0 ; n<1024 ; n++) |
| ofs[n] /= i; |
| for (i=0 ; i<10 ; i++) { |
| b->SoftTrigger(); |
| while (b->IsBusy()); |
| b->StartDomino(); |
| b->TransferWaves(1); |
| b->GetWave(0, 0, sw, 0, 0); |
| sx = sxx = 0; |
| for (n=10 ; n<1014 ; n++) { |
| sx += (sw[n]-ofs[n])/4096.0; |
| sxx += (sw[n]-ofs[n])/4096.0*(sw[n]-ofs[n])/4096.0; |
| } |
| if (i>5) |
| Sleep(5000); |
| avg = sx / n; |
| stdev = sqrt((sxx-sx*sx/n)/(n-1)); |
| enob = log(1/stdev)/log(2.); |
| printf("avg=%1.4lf sd=%1.4lf ENOB=%1.1lf\n", avg, stdev, enob); |
| }; |
| } |
| /* exit/quit ---------- */ |
| else if (match(param[0], "exit") || match(param[0], "quit")) |
| break; |
| else { |
| if (strchr(param[0], '\r')) |
| *strchr(param[0], '\r') = 0; |
| if (strchr(param[0], '\n')) |
| *strchr(param[0], '\n') = 0; |
| printf("Unknon command \"%s\"\n", param[0]); |
| } |
| } while (1); |
| delete drs; |
| } |
| /*------------------------------------------------------------------*/ |
| int main() |
| { |
| printf("DRS command line tool, Revision %d\n", atoi(drscl_svn_revision+15)); |
| printf("Type 'help' for a list of available commands.\n\n"); |
| cmd_loop(); |
| return 1; |
| } |
| /cvi/instr/drsctrl/drscl.exe |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |
| /cvi/instr/drsctrl/drscl.obj |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |
| /cvi/instr/drsctrl/drsread.c |
|---|
| 0,0 → 1,283 |
| #include <windows.h> |
| #include <drsread.h> |
| /* The two macros below are used as error return codes */ |
| /* in case the DLL does not load, or is missing one or */ |
| /* more functions, respectively. You must define them */ |
| /* to whatever values are meaningful for your DLL. */ |
| #define kFailedToLoadDLLError ??? |
| #define kCouldNotFindFunction ??? |
| static HINSTANCE DLLHandle; |
| /* Declare the variables that hold the addresses of the function */ |
| /* pointers. */ |
| static void (__cdecl *DRSSetMask_Ptr)(int mask); |
| static void (__cdecl *DRSSetTriggerType_Ptr)(int type); |
| static void (__cdecl *DRSSetFrequency_Ptr)(int freq); |
| static void (__cdecl *DRSSetRange_Ptr)(double range); |
| static void (__cdecl *DRSSetTriggerChannel_Ptr)(int channel); |
| static void (__cdecl *DRSSetTriggerDelay_Ptr)(double delay); |
| static void (__cdecl *DRSSetTriggerLevel_Ptr)(double level); |
| static void (__cdecl *DRSSetTriggerPolarity_Ptr)(int polarity); |
| static float *(__cdecl *DRSGetTime_Ptr)(int ch); |
| static float *(__cdecl *DRSGetWave_Ptr)(int ch); |
| static int (__cdecl *DRSInit_Ptr)(); |
| static int (__cdecl *DRSRead_Ptr)(int drstimer); |
| static int (__cdecl *DRSEnd_Ptr)(); |
| static int (__cdecl *DRSToBuffer_Ptr)(unsigned char *p, int m_evSerial); |
| static int (__cdecl *DRSIsTimeout_Ptr)(); |
| static void (__cdecl *DRSSetTimeout_Ptr)(); |
| static void (__cdecl *DRSSigInt_Ptr)(int k); |
| /* Load the DLL and get the addresses of the functions */ |
| static int LoadDLLIfNeeded(void) |
| { |
| if (DLLHandle) |
| return 0; |
| DLLHandle = LoadLibrary("drsread.dll"); |
| if (DLLHandle == NULL) { |
| return kFailedToLoadDLLError; |
| } |
| if (!(DRSSetMask_Ptr = (void*) GetProcAddress(DLLHandle, "DRSSetMask"))) |
| goto FunctionNotFoundError; |
| if (!(DRSSetTriggerType_Ptr = (void*) GetProcAddress(DLLHandle, |
| "DRSSetTriggerType"))) |
| goto FunctionNotFoundError; |
| if (!(DRSSetFrequency_Ptr = (void*) GetProcAddress(DLLHandle, |
| "DRSSetFrequency"))) |
| goto FunctionNotFoundError; |
| if (!(DRSSetRange_Ptr = (void*) GetProcAddress(DLLHandle, "DRSSetRange"))) |
| goto FunctionNotFoundError; |
| if (!(DRSSetTriggerChannel_Ptr = (void*) GetProcAddress(DLLHandle, |
| "DRSSetTriggerChannel"))) |
| goto FunctionNotFoundError; |
| if (!(DRSSetTriggerDelay_Ptr = (void*) GetProcAddress(DLLHandle, |
| "DRSSetTriggerDelay"))) |
| goto FunctionNotFoundError; |
| if (!(DRSSetTriggerLevel_Ptr = (void*) GetProcAddress(DLLHandle, |
| "DRSSetTriggerLevel"))) |
| goto FunctionNotFoundError; |
| if (!(DRSSetTriggerPolarity_Ptr = (void*) GetProcAddress(DLLHandle, |
| "DRSSetTriggerPolarity"))) |
| goto FunctionNotFoundError; |
| if (!(DRSGetTime_Ptr = (void*) GetProcAddress(DLLHandle, "DRSGetTime"))) |
| goto FunctionNotFoundError; |
| if (!(DRSGetWave_Ptr = (void*) GetProcAddress(DLLHandle, "DRSGetWave"))) |
| goto FunctionNotFoundError; |
| if (!(DRSInit_Ptr = (void*) GetProcAddress(DLLHandle, "DRSInit"))) |
| goto FunctionNotFoundError; |
| if (!(DRSRead_Ptr = (void*) GetProcAddress(DLLHandle, "DRSRead"))) |
| goto FunctionNotFoundError; |
| if (!(DRSEnd_Ptr = (void*) GetProcAddress(DLLHandle, "DRSEnd"))) |
| goto FunctionNotFoundError; |
| if (!(DRSToBuffer_Ptr = (void*) GetProcAddress(DLLHandle, "DRSToBuffer"))) |
| goto FunctionNotFoundError; |
| if (!(DRSIsTimeout_Ptr = (void*) GetProcAddress(DLLHandle, "DRSIsTimeout"))) |
| goto FunctionNotFoundError; |
| if (!(DRSSetTimeout_Ptr = (void*) GetProcAddress(DLLHandle, "DRSSetTimeout"))) |
| goto FunctionNotFoundError; |
| if (!(DRSSigInt_Ptr = (void*) GetProcAddress(DLLHandle, "DRSSigInt"))) |
| goto FunctionNotFoundError; |
| return 0; |
| FunctionNotFoundError: |
| FreeLibrary(DLLHandle); |
| DLLHandle = 0; |
| return kCouldNotFindFunction; |
| } |
| /* Glue Code for each of the DLL functions */ |
| void DRSSetMask(int mask) |
| { |
| int dllLoadError; |
| if (dllLoadError = LoadDLLIfNeeded()) |
| return; |
| (*DRSSetMask_Ptr)(mask); |
| } |
| void DRSSetTriggerType(int type) |
| { |
| int dllLoadError; |
| if (dllLoadError = LoadDLLIfNeeded()) |
| return; |
| (*DRSSetTriggerType_Ptr)(type); |
| } |
| void DRSSetFrequency(int freq) |
| { |
| int dllLoadError; |
| if (dllLoadError = LoadDLLIfNeeded()) |
| return; |
| (*DRSSetFrequency_Ptr)(freq); |
| } |
| void DRSSetRange(double range) |
| { |
| int dllLoadError; |
| if (dllLoadError = LoadDLLIfNeeded()) |
| return; |
| (*DRSSetRange_Ptr)(range); |
| } |
| void DRSSetTriggerChannel(int channel) |
| { |
| int dllLoadError; |
| if (dllLoadError = LoadDLLIfNeeded()) |
| return; |
| (*DRSSetTriggerChannel_Ptr)(channel); |
| } |
| void DRSSetTriggerDelay(double delay) |
| { |
| int dllLoadError; |
| if (dllLoadError = LoadDLLIfNeeded()) |
| return; |
| (*DRSSetTriggerDelay_Ptr)(delay); |
| } |
| void DRSSetTriggerLevel(double level) |
| { |
| int dllLoadError; |
| if (dllLoadError = LoadDLLIfNeeded()) |
| return; |
| (*DRSSetTriggerLevel_Ptr)(level); |
| } |
| void DRSSetTriggerPolarity(int polarity) |
| { |
| int dllLoadError; |
| if (dllLoadError = LoadDLLIfNeeded()) |
| return; |
| (*DRSSetTriggerPolarity_Ptr)(polarity); |
| } |
| float *DRSGetTime(int ch) |
| { |
| int dllLoadError; |
| if (dllLoadError = LoadDLLIfNeeded()) |
| return ???; |
| return (*DRSGetTime_Ptr)(ch); |
| } |
| float *DRSGetWave(int ch) |
| { |
| int dllLoadError; |
| if (dllLoadError = LoadDLLIfNeeded()) |
| return ???; |
| return (*DRSGetWave_Ptr)(ch); |
| } |
| int DRSInit() |
| { |
| int dllLoadError; |
| if (dllLoadError = LoadDLLIfNeeded()) |
| return dllLoadError; |
| return (*DRSInit_Ptr)(); |
| } |
| int DRSRead(int drstimer) |
| { |
| int dllLoadError; |
| if (dllLoadError = LoadDLLIfNeeded()) |
| return dllLoadError; |
| return (*DRSRead_Ptr)(drstimer); |
| } |
| int DRSEnd() |
| { |
| int dllLoadError; |
| if (dllLoadError = LoadDLLIfNeeded()) |
| return dllLoadError; |
| return (*DRSEnd_Ptr)(); |
| } |
| int DRSToBuffer(unsigned char *p, int m_evSerial) |
| { |
| int dllLoadError; |
| if (dllLoadError = LoadDLLIfNeeded()) |
| return dllLoadError; |
| return (*DRSToBuffer_Ptr)(p, m_evSerial); |
| } |
| int DRSIsTimeout() |
| { |
| int dllLoadError; |
| if (dllLoadError = LoadDLLIfNeeded()) |
| return dllLoadError; |
| return (*DRSIsTimeout_Ptr)(); |
| } |
| void DRSSetTimeout() |
| { |
| int dllLoadError; |
| if (dllLoadError = LoadDLLIfNeeded()) |
| return; |
| (*DRSSetTimeout_Ptr)(); |
| } |
| void DRSSigInt(int k) |
| { |
| int dllLoadError; |
| if (dllLoadError = LoadDLLIfNeeded()) |
| return; |
| (*DRSSigInt_Ptr)(k); |
| } |
| /cvi/instr/drsctrl/drsread.cpp |
|---|
| 0,0 → 1,620 |
| /********************************************************************\ |
| Name: drsread.cpp |
| Created by: Rok Pestotnik |
| Contents: Simple example application to read out a DRS4 |
| evaluation board and save into the data file |
| Interface dll for LabWindows CVI |
| \********************************************************************/ |
| #ifdef DLLMAIN |
| #define DLLEXPORT __declspec(dllexport) |
| #else |
| #define DLLEXPORT |
| #endif |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <math.h> |
| #include <time.h> |
| #include <signal.h> |
| #include <TFile.h> |
| #include <TH2F.h> |
| #include <TCanvas.h> |
| //#include <TApplication.h> |
| #ifdef _MSC_VER |
| #include "gettimeofday.h" |
| #include "timer.h" |
| #define DIR_SEPARATOR '\\' |
| #elif defined(OS_LINUX) || defined(OS_DARWIN) |
| #define O_BINARY 0 |
| #include <unistd.h> |
| #include <ctype.h> |
| #include <sys/ioctl.h> |
| #include <errno.h> |
| #define DIR_SEPARATOR '/' |
| #endif |
| #include "DRS.h" |
| #include "drsread.h" |
| /*------------------------------------------------------------------*/ |
| class drssettings { |
| static drssettings *s_instance; |
| public: |
| drssettings(){ |
| mask = 0xF; |
| range = 0; |
| trigger_type = 1; |
| sampling_frequency = 5; |
| trigger_delay = 0; |
| trigger_channel=0; |
| trigger_polarity=false; |
| trigger_level=0.05; |
| }; |
| ~drssettings(){}; |
| static drssettings *instance() |
| { |
| if (!s_instance) |
| s_instance = new drssettings; |
| return s_instance; |
| }; |
| unsigned char mask; |
| double range; |
| int trigger_type; // 0 software, 1 fast hardware, 2 slow hardware |
| int trigger_channel; |
| int sampling_frequency; |
| double trigger_delay; |
| double trigger_level; |
| bool trigger_polarity; |
| }; |
| drssettings *drssettings::s_instance = 0; |
| drssettings *DRSParameters; |
| DLLEXPORT void DRSSetMask(int mask){ drssettings::instance()->mask;}; |
| DLLEXPORT void DRSSetTriggerType(int type){ drssettings::instance()->trigger_type = type;}; |
| DLLEXPORT void DRSSetFrequency(int freq){ drssettings::instance()->sampling_frequency = freq;}; |
| DLLEXPORT void DRSSetRange(double range){ drssettings::instance()->range = range;}; |
| DLLEXPORT void DRSSetTriggerChannel(int channel){ drssettings::instance()->trigger_channel = channel;}; |
| DLLEXPORT void DRSSetTriggerDelay(double delay){ drssettings::instance()->trigger_delay = delay;}; |
| DLLEXPORT void DRSSetTriggerLevel(double level){ drssettings::instance()->trigger_level = level;}; |
| DLLEXPORT void DRSSetTriggerPolarity(int polarity){ drssettings::instance()->trigger_polarity = (polarity==1);}; |
| static int DRSTimeout; |
| DLLEXPORT int DRSIsTimeout() |
| { |
| return DRSTimeout; |
| } |
| DLLEXPORT void DRSSetTimeout ( void ) |
| { |
| DRSTimeout=1; |
| printf("->>> Timer Out !!!\n"); |
| } |
| static DRS *drs=NULL; |
| DLLEXPORT int DRSInit() |
| { |
| DRSBoard *b; |
| /* do drsinitial scan */ |
| drs = new DRS(); |
| if (!drs) return -1; |
| DRSParameters = drssettings::instance(); |
| /* show any found board(s) */ |
| for (int i=0 ; i<drs->GetNumberOfBoards() ; i++) { |
| b = drs->GetBoard(i); |
| printf("Found DRS4 evaluation board, serial #%d, firmware revision %d\n", |
| b->GetBoardSerialNumber(), b->GetFirmwareVersion()); |
| } |
| /* exit if no board found */ |
| int nBoards = drs->GetNumberOfBoards(); |
| if (nBoards == 0) { |
| printf("No DRS4 evaluation board found\n"); |
| return -2; |
| } |
| /* continue working with first board only */ |
| b = drs->GetBoard(0); |
| /* drsinitialize board */ |
| b->Init(); |
| /* set sampling frequency default 5 */ |
| b->SetFrequency(DRSParameters->sampling_frequency, true); |
| /* enable transparent mode needed for analog trigger */ |
| b->SetTranspMode(1); |
| /* set input range to -0.5V ... +0.5V -> range=0 */ |
| b->SetInputRange(DRSParameters->range); |
| /* use following line to set range to 0..1V */ |
| //b->SetInputRange(0.5); |
| /* use following line to turn on the internal 100 MHz clock connected to all channels */ |
| //b->EnableTcal(1); |
| /* kaj je to .... |
| // Set domino mode |
| // mode == 0: single sweep |
| // mode == 1: run continously -- default |
| b->SetDominoMode(1); |
| // Set domino activity |
| // mode == 0: stop during readout |
| // mode == 1: keep domino wave running -- default |
| // |
| b->SetDominoActive(1); |
| // Set readout mode |
| // mode == 0: start from first bin -- default |
| // mode == 1: start from domino stop |
| // |
| b->SetReadoutMode(1); |
| */ |
| /* use following lines to enable hardware trigger on CH1 at 50 mV positive edge */ |
| printf("Board Type:%d\n",b->GetBoardType() ); |
| if (b->GetBoardType() >= 8) { // Evaluaiton Board V4&5 |
| b->EnableTrigger(DRSParameters->trigger_type, 0); // enable hardware trigger - 1 fast trigger, 2 slow trigger, 0 disable hw trigger |
| b->SetTriggerSource(1<<DRSParameters->trigger_channel); // set CH1 as source // simple or of single channel |
| } else if (b->GetBoardType() == 7) { // Evaluation Board V3 |
| b->EnableTrigger(0, 1); // lemo off, analog trigger on |
| b->SetTriggerSource(0); // use CH1 as source |
| } |
| b->SetTriggerLevel(DRSParameters->trigger_level); // 0.05 V |
| b->SetTriggerPolarity(DRSParameters->trigger_polarity); // positive edge |
| /* use following lines to set individual trigger elvels */ |
| //b->SetIndividualTriggerLevel(1, 0.1); |
| //b->SetIndividualTriggerLevel(2, 0.2); |
| //b->SetIndividualTriggerLevel(3, 0.3); |
| //b->SetIndividualTriggerLevel(4, 0.4); |
| //b->SetTriggerSource(15); |
| b->SetTriggerDelayNs( DRSParameters->trigger_delay); // zero ns trigger delay |
| /* use following lines to enable the external trigger */ |
| //if (b->GetBoardType() == 8) { // Evaluaiton Board V4 |
| // b->EnableTrigger(1, 0); // enable hardware trigger |
| // b->SetTriggerSource(1<<4); // set external trigger as source |
| //} else { // Evaluation Board V3 |
| // b->EnableTrigger(1, 0); // lemo on, analog trigger off |
| // } |
| return 0; |
| } |
| static float DRSTimeArray[8][1024]; |
| static float DRSWaveArray[8][1024]; |
| DLLEXPORT float * DRSGetTime(int ch){ return DRSTimeArray[ch];} |
| DLLEXPORT float * DRSGetWave(int ch){ return DRSWaveArray[ch];} |
| DLLEXPORT int DRSRead( int DRStimer) |
| { |
| DRSBoard *b = drs->GetBoard(0); |
| /* wait for trigger */ |
| int tout=1000; /* timeout in mili seconds */ |
| DRSTimeout=0; |
| if (DRStimer) start_timer(tout, &DRSSetTimeout); |
| /* start board (activate domino wave) */ |
| b->StartDomino(); |
| if (!DRSParameters->trigger_type) b->SoftTrigger(); |
| while (b->IsBusy()){ |
| if (DRSTimeout) { |
| printf("Waiting for Trigger.. at line %d\n", __LINE__); |
| if (DRStimer) stop_timer(); |
| return -1; |
| } |
| }; |
| if (DRStimer) stop_timer(); |
| /* read all waveforms */ |
| b->TransferWaves(0, 8); |
| for (int k=0;k<4;k++){ |
| if (! (DRSParameters->mask & ( 0x1<<k )) ) continue; |
| /* Note: On the evaluation board input #1 is connected to channel 0 and 1 of |
| the DRS chip, input #2 is connected to channel 2 and 3 and so on. So to |
| get the input #2 we have to read DRS channel #2, not #1. */ |
| /* read time (X) array of k-th channel in ns and waveform (Y) array of k-th channel in mV */ |
| b->GetTime(0, 2*k, b->GetTriggerCell(DRSParameters->trigger_channel), DRSTimeArray[k]); |
| b->GetWave(0, 2*k, DRSWaveArray[k]); |
| } |
| return 0; |
| } |
| DLLEXPORT int DRSEnd(){ |
| /* delete DRS object -> close USB connection */ |
| if (drs) delete drs; |
| drs = NULL; |
| return 0; |
| } |
| DLLEXPORT int DRSToBuffer( unsigned char *p, int m_evSerial ) |
| { |
| unsigned short d; |
| float t; |
| unsigned char *p0 = p; |
| int m_nBoards = drs->GetNumberOfBoards(); |
| int m_waveDepth = 1024 ;// 2048 |
| int m_inputRange = drs->GetBoard(0)->GetInputRange(); |
| time_t rawtime; |
| time ( &rawtime ); |
| struct tm m_evTimestamp; |
| m_evTimestamp = *(localtime ( &rawtime )); |
| struct timeval mtime; |
| gettimeofday(&mtime, NULL); |
| if (m_evSerial == 0) { |
| // time calibration header |
| memcpy(p, "TIME", 4); |
| p += 4; |
| for (int b=0 ; b<m_nBoards ; b++) { |
| // store board serial number |
| sprintf((char *)p, "B#"); |
| p += 2; |
| *(unsigned short *)p = drs->GetBoard(b)->GetBoardSerialNumber(); |
| p += sizeof(unsigned short); |
| for (int i=0 ; i<4 ; i++) { |
| if (DRSParameters->mask & (0x1<<i)) { |
| sprintf((char *)p, "C%03d", i+1); |
| p += 4; |
| float tcal[2048]; |
| drs->GetBoard(b)->GetTimeCalibration(0, i*2, 0, tcal, 0); |
| for (int j=0 ; j<m_waveDepth ; j++) { |
| // save binary time as 32-bit float value |
| if (m_waveDepth == 2048) { |
| t = (tcal[j]+tcal[j+1])/2; |
| j++; |
| } else |
| t = tcal[j]; |
| *(float *)p = t; |
| p += sizeof(float); |
| } |
| } |
| } |
| } |
| } |
| memcpy(p, "EHDR", 4); |
| p += 4; |
| *(int *)p = m_evSerial; |
| p += sizeof(int); |
| *(unsigned short *)p = m_evTimestamp.tm_year; |
| p += sizeof(unsigned short); |
| *(unsigned short *)p = m_evTimestamp.tm_mon; |
| p += sizeof(unsigned short); |
| *(unsigned short *)p = m_evTimestamp.tm_mday; |
| p += sizeof(unsigned short); |
| *(unsigned short *)p = m_evTimestamp.tm_hour; |
| p += sizeof(unsigned short); |
| *(unsigned short *)p = m_evTimestamp.tm_min; |
| p += sizeof(unsigned short); |
| *(unsigned short *)p = m_evTimestamp.tm_sec; |
| p += sizeof(unsigned short); |
| *(unsigned short *)p = mtime.tv_usec/1000; |
| p += sizeof(unsigned short); |
| *(unsigned short *)p = (unsigned short)(m_inputRange * 1000); // range |
| p += sizeof(unsigned short); |
| int b=0; // only for board 0 |
| // store board serial number |
| sprintf((char *)p, "B#"); |
| p += 2; |
| *(unsigned short *)p = drs->GetBoard(b)->GetBoardSerialNumber(); |
| p += sizeof(unsigned short); |
| // store trigger cell |
| sprintf((char *)p, "T#"); |
| p += 2; |
| *(unsigned short *)p = drs->GetBoard(b)->GetTriggerCell(DRSParameters->trigger_channel); |
| p += sizeof(unsigned short); |
| for (int i=0 ; i<4 ; i++) { |
| if (DRSParameters->mask & (0x1<<i)) { |
| sprintf((char *)p, "C%03d", i+1); |
| p += 4; |
| for (int j=0 ; j<m_waveDepth ; j++) { |
| // save binary date as 16-bit value: |
| // 0 = -0.5V, 65535 = +0.5V for range 0 |
| // 0 = -0.05V, 65535 = +0.95V for range 0.45 |
| if (m_waveDepth == 2048) { |
| // in cascaded mode, save 1024 values as averages of the 2048 values |
| d = (unsigned short)(((DRSWaveArray[i][j]+DRSWaveArray[i][j+1])/2000.0 - m_inputRange + 0.5) * 65535); |
| *(unsigned short *)p = d; |
| p += sizeof(unsigned short); |
| j++; |
| } else { |
| d = (unsigned short)((DRSWaveArray[i][j]/1000.0 - m_inputRange + 0.5) * 65535); |
| *(unsigned short *)p = d; |
| p += sizeof(unsigned short); |
| } |
| } |
| } |
| } |
| return (p-p0); // return number of bytes |
| } |
| #ifdef MAIN |
| #include "XGetopt.h" |
| #include "getopt.h" |
| TH2F *h[4]; |
| typedef struct { |
| char recid[4]; |
| unsigned int posx, posy, posz; |
| unsigned int iposx, iposy, iposz; |
| } POSREC; |
| int help() { |
| printf ("*********************************************************************************:\n"); |
| printf ("Usage: Read of the DRS4 PSI board and dump of the waveforms in the file:\n\n"); |
| printf ("Arguments: \n"); |
| printf ("-v verbosity \n"); |
| printf ("-a output rootfile \n"); |
| printf ("-o output filename \n"); |
| printf ("-r output root filename \n"); |
| printf ("-n number of events\n"); |
| printf ("-m channel bit mask\n"); |
| printf ("-h trigger type (0 software, 1 fast hardware, 2 slow hardware)\n"); |
| printf ("-d trigger delay in ns\n"); |
| printf ("-f sampling frequency\n"); |
| printf ("-t trigger channel\n"); |
| printf ("-l trigger level\n"); |
| printf ("-p trigger polarity (0 positive\n"); |
| printf ("*********************************************************************************:\n"); |
| printf ("Examples:\n\n"); |
| return 0; |
| } |
| char filename[0xFF]=""; |
| char rootfile[0xFF]=""; |
| int neve = 0; |
| int verbose = 0; |
| void Init(int argc, char **argv){ |
| DRSParameters = drssettings::instance(); |
| char c; |
| extern char *optarg; |
| extern int optind; |
| extern int optopt; |
| while ((c = getopt (argc, argv, "a:o:v:m:n:f:d:r:h:t:p:l:")) != -1){ |
| switch (c) |
| { |
| case 'a': |
| sprintf(rootfile,"%s", optarg ); |
| break; // root output |
| case 'o': |
| sprintf(filename,"%s", optarg ); |
| break; // output |
| case 'v': |
| verbose = atoi(optarg); |
| break; // verbosity |
| case 'm':{ |
| unsigned long ul = strtoul (optarg,NULL,0); |
| DRSSetMask( (unsigned char)( ul & 0xF ) ) ; |
| break; |
| } // channel mask |
| case 'n': |
| neve = atoi (optarg); |
| break; // number of events or number of scan points |
| case 'f': |
| DRSSetFrequency( atoi (optarg) ); |
| break; // sampling frequency |
| case 'd': |
| DRSSetTriggerDelay( atof (optarg) ); |
| break; // trigger delay |
| case 'p': |
| DRSSetTriggerPolarity( atoi (optarg)); |
| break; // trigger polarity |
| case 'l': |
| DRSSetTriggerLevel(atoi (optarg)); |
| break; // trigger level |
| case 'r': |
| DRSSetRange ( atof (optarg) ); |
| break; // range |
| case 'h': |
| DRSSetTriggerType( atoi (optarg) ); |
| break; // send sotware trigger before reading out the dat |
| case 't': |
| DRSSetTriggerChannel( atoi(optarg) ); |
| break; // trigger channel |
| case '?': |
| if (optopt == 'c') |
| fprintf (stderr, "Option -%c requires an argument.\n", optopt); |
| else if (isprint (optopt)) |
| fprintf (stderr, "Unknown option `-%c'.\n", optopt); |
| else |
| fprintf (stderr, |
| "Unknown option character `\\x%x'.\n", |
| optopt); |
| abort (); |
| default: |
| abort (); |
| } |
| } |
| //for (int i=optind; i<argc; i++) data = strtoul (argv[i],NULL,0); |
| } |
| int ctrl_c=0; |
| DLLEXPORT void DRSSigInt ( int ) |
| { |
| ctrl_c = 1; |
| printf("->>> CTRL+c !!!\n"); |
| } |
| //#ifdef __CINT__ |
| int main(int argc, char **argv){ |
| //#else |
| //int drsread(int argc, char **argv){ |
| //#endif |
| if (signal (SIGINT, DRSSigInt) == SIG_ERR) { |
| perror ("sigignore"); |
| } |
| Init(argc, argv); |
| if (argc==1) { help(); return 0; } |
| FILE *fp=NULL; |
| if (strlen(filename)>0) { |
| if (verbose) printf("Data in the file:%s\n", filename); |
| fp=fopen(filename,"wb"); |
| } |
| TFile *rfile= NULL; |
| if (strlen(rootfile)>0) { |
| if (verbose) printf("Data in the file:%s\n", rootfile); |
| rfile = new TFile(rootfile,"RECREATE"); |
| } |
| TCanvas *c = new TCanvas(); c->Divide(2,2); |
| c->Draw(); |
| for (int i=0;i<4;i++){ |
| if (! (DRSParameters->mask & ( 0x1<<i )) ) continue; |
| char name[0xff]; |
| sprintf(name,"h%d",i); |
| h[i]=new TH2F(name,name,1024,0,204,1024,-0.6+DRSParameters->range,0.6+DRSParameters->range); |
| c->cd(i+1); h[i]->Draw("colz"); |
| } |
| //--------------------------------------- |
| static unsigned char *buffer; |
| static int buffer_size = 0; |
| const int nBoards=1; |
| const int waveDepth=1024; |
| if (buffer_size == 0) { |
| buffer_size = 4 + nBoards * (4 + 4*(4+waveDepth*4)); |
| buffer_size += 24 + nBoards * (8 + 4*(4+waveDepth*2)); |
| buffer = (unsigned char *)malloc(buffer_size); |
| } |
| time_t t,told, tstart; |
| if (!DRSInit()){ |
| time(&tstart); |
| told=tstart; |
| int i=0; |
| for (i=0; i<neve; i++) { |
| int nb = (DRSRead(1) == 0 && fp ) ? DRSToBuffer( buffer , i ) : 0; |
| if (DRSTimeout) i--; |
| if (ctrl_c) break; |
| time(&t); |
| if (t!=told ) { |
| printf("%d events in %2.2f min (%d s) %s",i+1, (double)(t-tstart)/60.,int(t-tstart), ctime(&t)); |
| c->Modified(); c->Update(); |
| } |
| told=t; |
| // Save data |
| if (nb>0 && fp) fwrite(buffer, 1,nb ,fp); |
| // Plot Data |
| for (int k=0;k<4;k++){ |
| if (! (DRSParameters->mask & ( 0x1<<k )) ) continue; |
| float *t=DRSGetTime(k); |
| float *x=DRSGetWave(k); |
| for (int i=0 ; i<1024 ; i++) { |
| if (verbose) printf("[%d] %d. x= %3.2f y=%3.2f\n", k, i, t[i], x[i] ); |
| h[k]->Fill( t[i], x[i]*1e-3); |
| } |
| } |
| } |
| time(&t); |
| printf("%d events in %2.2f min (%d s) %s",i+1, (double)(t-tstart)/60.,int(t-tstart), ctime(&t)); |
| DRSEnd(); |
| } |
| //--------------------------------------- |
| if (rfile !=NULL) rfile->Write(); |
| if (fp) fclose(fp); |
| if (c) c->SaveAs("drsread.pdf"); |
| // TApplication* theApp = new TApplication("App", NULL, NULL); |
| // theApp->Run(); |
| } |
| #endif |
| /cvi/instr/drsctrl/drsread.dll |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |
| /cvi/instr/drsctrl/drsread.exe |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |
| /cvi/instr/drsctrl/drsread.exp |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |
| /cvi/instr/drsctrl/drsread.h |
|---|
| 0,0 → 1,31 |
| #ifndef _DRSREAD_H_ |
| #define _DRSREAD_H_ |
| #ifdef DLLMAIN |
| #define DLLEXPORT extern "C" __declspec(dllexport) |
| #else |
| //#define DLLEXPORT __declspec(dllimport) |
| #define DLLEXPORT |
| #endif |
| DLLEXPORT void DRSSetMask(int mask); |
| DLLEXPORT void DRSSetTriggerType(int type); |
| DLLEXPORT void DRSSetFrequency(int freq); |
| DLLEXPORT void DRSSetRange(double range); |
| DLLEXPORT void DRSSetTriggerChannel(int channel); |
| DLLEXPORT void DRSSetTriggerDelay(double delay); |
| DLLEXPORT void DRSSetTriggerLevel(double level); |
| DLLEXPORT void DRSSetTriggerPolarity(int polarity); |
| DLLEXPORT float * DRSGetTime(int ch); |
| DLLEXPORT float * DRSGetWave(int ch); |
| DLLEXPORT int DRSInit(); |
| DLLEXPORT int DRSRead( int drstimer); |
| DLLEXPORT int DRSEnd(); |
| DLLEXPORT int DRSToBuffer( unsigned char *p, int m_evSerial ); |
| DLLEXPORT int DRSIsTimeout(); |
| DLLEXPORT void DRSSetTimeout ( void ); |
| DLLEXPORT void DRSSigInt ( int k ); |
| #endif |
| /cvi/instr/drsctrl/drsread.lib |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |
| /cvi/instr/drsctrl/drsread.obj |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |
| /cvi/instr/drsctrl/getopt.h |
|---|
| 0,0 → 1,74 |
| /*- |
| * Copyright (c) 2000 The NetBSD Foundation, Inc. |
| * All rights reserved. |
| * |
| * This code is derived from software contributed to The NetBSD Foundation |
| * by Dieter Baron and Thomas Klausner. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
| * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
| * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| * |
| * $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ |
| */ |
| #ifndef _GETOPT_H_ |
| #define _GETOPT_H_ |
| /* |
| * Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions |
| */ |
| #define no_argument 0 |
| #define required_argument 1 |
| #define optional_argument 2 |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| struct option { |
| /* name of long option */ |
| const char *name; |
| /* |
| * one of no_argument, required_argument, and optional_argument: |
| * whether option takes an argument |
| */ |
| int has_arg; |
| /* if not NULL, set *flag to val when option found */ |
| int *flag; |
| /* if flag not NULL, value to set *flag to; else return value */ |
| int val; |
| }; |
| int getopt_long(int, char * const *, const char *, |
| const struct option *, int *); |
| extern int optreset; |
| extern char *optarg; |
| extern int opterr; |
| extern int optind; |
| extern int optopt; |
| #ifdef __cplusplus |
| }; |
| #endif |
| #endif /* !_GETOPT_H_ */ |
| /cvi/instr/drsctrl/getopt_long.c |
|---|
| 0,0 → 1,466 |
| /*- |
| * Copyright (c) 2000 The NetBSD Foundation, Inc. |
| * All rights reserved. |
| * |
| * This code is derived from software contributed to The NetBSD Foundation |
| * by Dieter Baron and Thomas Klausner. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
| * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
| * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| * |
| * $NetBSD: getopt_long.c,v 1.3 2008/04/29 05:46:09 martin Exp $ |
| */ |
| #include <assert.h> |
| #include <errno.h> |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include "getopt.h" |
| #ifndef _DIAGASSERT |
| #define _DIAGASSERT(e) |
| #endif |
| int opterr = 1; /* if error message should be printed */ |
| int optind = 1; /* index into parent argv vector */ |
| int optopt = '?'; /* character checked for validity */ |
| int optreset; /* reset getopt */ |
| char *optarg; /* argument associated with option */ |
| #define IGNORE_FIRST (*options == '-' || *options == '+') |
| #define PRINT_ERROR ((opterr) && ((*options != ':') \ |
| || (IGNORE_FIRST && options[1] != ':'))) |
| #define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL) |
| #define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST) |
| /* XXX: GNU ignores PC if *options == '-' */ |
| #define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-') |
| /* return values */ |
| #define BADCH (int)'?' |
| #define BADARG (int)':' |
| #define INORDER (int)1 |
| #define EMSG "" |
| static int getopt_internal(int, char * const *, const char *); |
| static int gcd(int, int); |
| static void permute_args(int, int, int, char * const *); |
| static void xwarnx(const char *, ...); |
| static char *place = EMSG; /* option letter processing */ |
| /* XXX: set optreset to 1 rather than these two */ |
| static int nonopt_start = -1; /* first non option argument (for permute) */ |
| static int nonopt_end = -1; /* first option after non options (for permute) */ |
| /* Error messages */ |
| static const char recargchar[] = "option requires an argument -- %c"; |
| static const char recargstring[] = "option requires an argument -- %s"; |
| static const char ambig[] = "ambiguous option -- %.*s"; |
| static const char noarg[] = "option doesn't take an argument -- %.*s"; |
| static const char illoptchar[] = "illegal option -- %c"; |
| static const char illoptstring[] = "illegal option -- %s"; |
| static const char *progname; |
| /* Replacement for warnx(3) for systems without it. */ |
| static void xwarnx(const char *fmt, ...) { |
| va_list ap; |
| va_start(ap, fmt); |
| if (progname) |
| (void) fprintf(stderr, "%s: ", progname); |
| if (fmt) |
| (void) vfprintf(stderr, fmt, ap); |
| (void) fprintf(stderr, "\n"); |
| va_end(ap); |
| } |
| /* |
| * Compute the greatest common divisor of a and b. |
| */ |
| static int |
| gcd(int a, int b) |
| { |
| int c; |
| c = a % b; |
| while (c != 0) { |
| a = b; |
| b = c; |
| c = a % b; |
| } |
| return b; |
| } |
| /* |
| * Exchange the block from nonopt_start to nonopt_end with the block |
| * from nonopt_end to opt_end (keeping the same order of arguments |
| * in each block). |
| */ |
| static void |
| permute_args(int nonopt_start, int nonopt_end, int opt_end, char * const *nargv) |
| { |
| int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; |
| char *swap; |
| /* |
| * compute lengths of blocks and number and size of cycles |
| */ |
| nnonopts = nonopt_end - nonopt_start; |
| nopts = opt_end - nonopt_end; |
| ncycle = gcd(nnonopts, nopts); |
| cyclelen = (opt_end - nonopt_start) / ncycle; |
| for (i = 0; i < ncycle; i++) { |
| cstart = nonopt_end+i; |
| pos = cstart; |
| for (j = 0; j < cyclelen; j++) { |
| if (pos >= nonopt_end) |
| pos -= nnonopts; |
| else |
| pos += nopts; |
| swap = nargv[pos]; |
| /* LINTED const cast */ |
| ((char **) nargv)[pos] = nargv[cstart]; |
| /* LINTED const cast */ |
| ((char **)nargv)[cstart] = swap; |
| } |
| } |
| } |
| /* |
| * getopt_internal -- |
| * Parse argc/argv argument vector. Called by user level routines. |
| * Returns -2 if -- is found (can be long option or end of options marker). |
| */ |
| static int |
| getopt_internal(int nargc, char * const *nargv, const char *options) |
| { |
| char *oli; /* option letter list index */ |
| int optchar; |
| _DIAGASSERT(nargv != NULL); |
| _DIAGASSERT(options != NULL); |
| optarg = NULL; |
| /* |
| * XXX Some programs (like rsyncd) expect to be able to |
| * XXX re-initialize optind to 0 and have getopt_long(3) |
| * XXX properly function again. Work around this braindamage. |
| */ |
| if (optind == 0) |
| optind = 1; |
| if (optreset) |
| nonopt_start = nonopt_end = -1; |
| start: |
| if (optreset || !*place) { /* update scanning pointer */ |
| optreset = 0; |
| if (optind >= nargc) { /* end of argument vector */ |
| place = EMSG; |
| if (nonopt_end != -1) { |
| /* do permutation, if we have to */ |
| permute_args(nonopt_start, nonopt_end, |
| optind, nargv); |
| optind -= nonopt_end - nonopt_start; |
| } |
| else if (nonopt_start != -1) { |
| /* |
| * If we skipped non-options, set optind |
| * to the first of them. |
| */ |
| optind = nonopt_start; |
| } |
| nonopt_start = nonopt_end = -1; |
| return -1; |
| } |
| if (*(place = nargv[optind]) != '-') { /* found non-option */ |
| place = EMSG; |
| if (IN_ORDER) { |
| /* |
| * GNU extension: |
| * return non-option as argument to option 1 |
| */ |
| optarg = nargv[optind++]; |
| return INORDER; |
| } |
| if (!PERMUTE) { |
| /* |
| * if no permutation wanted, stop parsing |
| * at first non-option |
| */ |
| return -1; |
| } |
| /* do permutation */ |
| if (nonopt_start == -1) |
| nonopt_start = optind; |
| else if (nonopt_end != -1) { |
| permute_args(nonopt_start, nonopt_end, |
| optind, nargv); |
| nonopt_start = optind - |
| (nonopt_end - nonopt_start); |
| nonopt_end = -1; |
| } |
| optind++; |
| /* process next argument */ |
| goto start; |
| } |
| if (nonopt_start != -1 && nonopt_end == -1) |
| nonopt_end = optind; |
| if (place[1] && *++place == '-') { /* found "--" */ |
| place++; |
| return -2; |
| } |
| } |
| if ((optchar = (int)*place++) == (int)':' || |
| (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) { |
| /* option letter unknown or ':' */ |
| if (!*place) |
| ++optind; |
| if (PRINT_ERROR) |
| xwarnx(illoptchar, optchar); |
| optopt = optchar; |
| return BADCH; |
| } |
| if (optchar == 'W' && oli[1] == ';') { /* -W long-option */ |
| /* XXX: what if no long options provided (called by getopt)? */ |
| if (*place) |
| return -2; |
| if (++optind >= nargc) { /* no arg */ |
| place = EMSG; |
| if (PRINT_ERROR) |
| xwarnx(recargchar, optchar); |
| optopt = optchar; |
| /* XXX: GNU returns '?' if options[0] != ':' */ |
| return BADARG; |
| } else /* white space */ |
| place = nargv[optind]; |
| /* |
| * Handle -W arg the same as --arg (which causes getopt to |
| * stop parsing). |
| */ |
| return -2; |
| } |
| if (*++oli != ':') { /* doesn't take argument */ |
| if (!*place) |
| ++optind; |
| } else { /* takes (optional) argument */ |
| optarg = NULL; |
| if (*place) /* no white space */ |
| optarg = place; |
| /* XXX: disable test for :: if PC? (GNU doesn't) */ |
| else if (oli[1] != ':') { /* arg not optional */ |
| if (++optind >= nargc) { /* no arg */ |
| place = EMSG; |
| if (PRINT_ERROR) |
| xwarnx(recargchar, optchar); |
| optopt = optchar; |
| /* XXX: GNU returns '?' if options[0] != ':' */ |
| return BADARG; |
| } else |
| optarg = nargv[optind]; |
| } |
| place = EMSG; |
| ++optind; |
| } |
| /* dump back option letter */ |
| return optchar; |
| } |
| /* |
| * getopt -- |
| * Parse argc/argv argument vector. |
| * |
| * [eventually this will replace the real getopt] |
| */ |
| int |
| getopt(int nargc, char * const *nargv, const char *options) |
| { |
| int retval; |
| progname = nargv[0]; |
| if ((retval = getopt_internal(nargc, nargv, options)) == -2) { |
| ++optind; |
| /* |
| * We found an option (--), so if we skipped non-options, |
| * we have to permute. |
| */ |
| if (nonopt_end != -1) { |
| permute_args(nonopt_start, nonopt_end, optind, |
| nargv); |
| optind -= nonopt_end - nonopt_start; |
| } |
| nonopt_start = nonopt_end = -1; |
| retval = -1; |
| } |
| return retval; |
| } |
| /* |
| * getopt_long -- |
| * Parse argc/argv argument vector. |
| */ |
| int |
| getopt_long(int nargc, |
| char * const *nargv, |
| const char *options, |
| const struct option *long_options, |
| int *idx) |
| { |
| int retval; |
| _DIAGASSERT(nargv != NULL); |
| _DIAGASSERT(options != NULL); |
| _DIAGASSERT(long_options != NULL); |
| /* idx may be NULL */ |
| progname = nargv[0]; |
| if ((retval = getopt_internal(nargc, nargv, options)) == -2) { |
| char *current_argv, *has_equal; |
| size_t current_argv_len; |
| int i, match; |
| current_argv = place; |
| match = -1; |
| optind++; |
| place = EMSG; |
| if (*current_argv == '\0') { /* found "--" */ |
| /* |
| * We found an option (--), so if we skipped |
| * non-options, we have to permute. |
| */ |
| if (nonopt_end != -1) { |
| permute_args(nonopt_start, nonopt_end, |
| optind, nargv); |
| optind -= nonopt_end - nonopt_start; |
| } |
| nonopt_start = nonopt_end = -1; |
| return -1; |
| } |
| if ((has_equal = strchr(current_argv, '=')) != NULL) { |
| /* argument found (--option=arg) */ |
| current_argv_len = has_equal - current_argv; |
| has_equal++; |
| } else |
| current_argv_len = strlen(current_argv); |
| for (i = 0; long_options[i].name; i++) { |
| /* find matching long option */ |
| if (strncmp(current_argv, long_options[i].name, |
| current_argv_len)) |
| continue; |
| if (strlen(long_options[i].name) == |
| (unsigned)current_argv_len) { |
| /* exact match */ |
| match = i; |
| break; |
| } |
| if (match == -1) /* partial match */ |
| match = i; |
| else { |
| /* ambiguous abbreviation */ |
| if (PRINT_ERROR) |
| xwarnx(ambig, (int)current_argv_len, |
| current_argv); |
| optopt = 0; |
| return BADCH; |
| } |
| } |
| if (match != -1) { /* option found */ |
| if (long_options[match].has_arg == no_argument |
| && has_equal) { |
| if (PRINT_ERROR) |
| xwarnx(noarg, (int)current_argv_len, |
| current_argv); |
| /* |
| * XXX: GNU sets optopt to val regardless of |
| * flag |
| */ |
| if (long_options[match].flag == NULL) |
| optopt = long_options[match].val; |
| else |
| optopt = 0; |
| /* XXX: GNU returns '?' if options[0] != ':' */ |
| return BADARG; |
| } |
| if (long_options[match].has_arg == required_argument || |
| long_options[match].has_arg == optional_argument) { |
| if (has_equal) |
| optarg = has_equal; |
| else if (long_options[match].has_arg == |
| required_argument) { |
| /* |
| * optional argument doesn't use |
| * next nargv |
| */ |
| optarg = nargv[optind++]; |
| } |
| } |
| if ((long_options[match].has_arg == required_argument) |
| && (optarg == NULL)) { |
| /* |
| * Missing argument; leading ':' |
| * indicates no error should be generated |
| */ |
| if (PRINT_ERROR) |
| xwarnx(recargstring, current_argv); |
| /* |
| * XXX: GNU sets optopt to val regardless |
| * of flag |
| */ |
| if (long_options[match].flag == NULL) |
| optopt = long_options[match].val; |
| else |
| optopt = 0; |
| /* XXX: GNU returns '?' if options[0] != ':' */ |
| --optind; |
| return BADARG; |
| } |
| } else { /* unknown option */ |
| if (PRINT_ERROR) |
| xwarnx(illoptstring, current_argv); |
| optopt = 0; |
| return BADCH; |
| } |
| if (long_options[match].flag) { |
| *long_options[match].flag = long_options[match].val; |
| retval = 0; |
| } else |
| retval = long_options[match].val; |
| if (idx) |
| *idx = match; |
| } |
| return retval; |
| } |
| /cvi/instr/drsctrl/getopt_long.obj |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |
| /cvi/instr/drsctrl/gettimeofday.c |
|---|
| 0,0 → 1,57 |
| /* |
| * gettimeofday.c |
| * Win32 gettimeofday() replacement |
| * |
| * src/port/gettimeofday.c |
| * |
| * Copyright (c) 2003 SRA, Inc. |
| * Copyright (c) 2003 SKC, Inc. |
| * |
| * Permission to use, copy, modify, and distribute this software and |
| * its documentation for any purpose, without fee, and without a |
| * written agreement is hereby granted, provided that the above |
| * copyright notice and this paragraph and the following two |
| * paragraphs appear in all copies. |
| * |
| * IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, |
| * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING |
| * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS |
| * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED |
| * OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS |
| * IS" BASIS, AND THE AUTHOR HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, |
| * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
| */ |
| //#include "c.h" |
| #include <windows.h> |
| #include <time.h> |
| /* FILETIME of Jan 1 1970 00:00:00. */ |
| static const unsigned __int64 epoch = ((unsigned __int64) 116444736000000000ULL); |
| /* |
| * timezone information is stored outside the kernel so tzp isn't used anymore. |
| * |
| * Note: this function is not for Win32 high precision timing purpose. See |
| * elapsed_time(). |
| */ |
| int gettimeofday(struct timeval * tp, struct timezone * tzp){ |
| FILETIME file_time; |
| SYSTEMTIME system_time; |
| ULARGE_INTEGER ularge; |
| GetSystemTime(&system_time); |
| SystemTimeToFileTime(&system_time, &file_time); |
| ularge.LowPart = file_time.dwLowDateTime; |
| ularge.HighPart = file_time.dwHighDateTime; |
| tp->tv_sec = (long) ((ularge.QuadPart - epoch) / 10000000L); |
| tp->tv_usec = (long) (system_time.wMilliseconds * 1000); |
| return 0; |
| } |
| /cvi/instr/drsctrl/gettimeofday.h |
|---|
| 0,0 → 1,12 |
| #ifndef _GETTIMEOFDAY_H_ |
| #define _GETTIMEOFDAY_H_ |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| int gettimeofday(struct timeval * tp, struct timezone * tzp); |
| #ifdef __cplusplus |
| } |
| #endif |
| #endif |
| /cvi/instr/drsctrl/gettimeofday.obj |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |
| /cvi/instr/drsctrl/gui.cpp |
|---|
| 0,0 → 1,503 |
| // By ROOT version 5.17/02 on 2008-03-13 06:46:41 |
| #ifndef ROOT_TGDockableFrame |
| #include "TGDockableFrame.h" |
| #endif |
| #ifndef ROOT_TGMenu |
| #include "TGMenu.h" |
| #endif |
| #ifndef ROOT_TGMdiDecorFrame |
| #include "TGMdiDecorFrame.h" |
| #endif |
| #ifndef ROOT_TG3DLine |
| #include "TG3DLine.h" |
| #endif |
| #ifndef ROOT_TGMdiFrame |
| #include "TGMdiFrame.h" |
| #endif |
| #ifndef ROOT_TGMdiMainFrame |
| #include "TGMdiMainFrame.h" |
| #endif |
| //#ifndef ROOT_TGuiBldHintsButton |
| //#include "TGuiBldHintsButton.h" |
| //#endif |
| #ifndef ROOT_TGMdiMenu |
| #include "TGMdiMenu.h" |
| #endif |
| #ifndef ROOT_TGListBox |
| #include "TGListBox.h" |
| #endif |
| #ifndef ROOT_TGNumberEntry |
| #include "TGNumberEntry.h" |
| #endif |
| #ifndef ROOT_TGScrollBar |
| #include "TGScrollBar.h" |
| #endif |
| //#ifndef ROOT_TGuiBldHintsEditor |
| //#include "TGuiBldHintsEditor.h" |
| //#endif |
| #ifndef ROOT_TRootBrowser |
| #include "TRootBrowser.h" |
| #endif |
| #ifndef ROOT_TGFrame |
| #include "TGFrame.h" |
| #endif |
| #ifndef ROOT_TGFileDialog |
| #include "TGFileDialog.h" |
| #endif |
| #ifndef ROOT_TGShutter |
| #include "TGShutter.h" |
| #endif |
| #ifndef ROOT_TGButtonGroup |
| #include "TGButtonGroup.h" |
| #endif |
| #ifndef ROOT_TGCanvas |
| #include "TGCanvas.h" |
| #endif |
| #ifndef ROOT_TGFSContainer |
| #include "TGFSContainer.h" |
| #endif |
| #ifndef ROOT_TGButton |
| #include "TGButton.h" |
| #endif |
| //#ifndef ROOT_TGuiBldEditor |
| //#include "TGuiBldEditor.h" |
| //#endif |
| #ifndef ROOT_TGTextEdit |
| #include "TGTextEdit.h" |
| #endif |
| #ifndef ROOT_TGFSComboBox |
| #include "TGFSComboBox.h" |
| #endif |
| #ifndef ROOT_TGLabel |
| #include "TGLabel.h" |
| #endif |
| #ifndef ROOT_TGView |
| #include "TGView.h" |
| #endif |
| //#ifndef ROOT_TRootGuiBuilder |
| //#include "TRootGuiBuilder.h" |
| //#endif |
| #ifndef ROOT_TGTab |
| #include "TGTab.h" |
| #endif |
| #ifndef ROOT_TGListView |
| #include "TGListView.h" |
| #endif |
| #ifndef ROOT_TGSplitter |
| #include "TGSplitter.h" |
| #endif |
| #ifndef ROOT_TGStatusBar |
| #include "TGStatusBar.h" |
| #endif |
| #ifndef ROOT_TGListTree |
| #include "TGListTree.h" |
| #endif |
| #ifndef ROOT_TGToolTip |
| #include "TGToolTip.h" |
| #endif |
| #ifndef ROOT_TGToolBar |
| #include "TGToolBar.h" |
| #endif |
| #ifndef ROOT_TRootEmbeddedCanvas |
| #include "TRootEmbeddedCanvas.h" |
| #endif |
| #ifndef ROOT_TCanvas |
| #include "TCanvas.h" |
| #endif |
| //#ifndef ROOT_TGuiBldDragManager |
| //#include "TGuiBldDragManager.h" |
| //#endif |
| #include "Riostream.h" |
| #include "TThread.h" |
| #include "TApplication.h" |
| #include "TROOT.h" |
| #include "TGraph.h" |
| #include "TH1F.h" |
| //#include "daq.h" |
| TGTextButton *gTextButton[10]; |
| TCanvas *fCanvas; |
| TGMainFrame *fMain; |
| TGTextEntry *gFilename; |
| TGNumberEntry *gCh; |
| TGTextEntry *gTimeDisplay; |
| TGCheckButton *gDebugButton; |
| TGNumberEntry *gMaxEve; |
| TGNumberEntry *gNeve; |
| TGNumberEntry *gMask; |
| TGNumberEntry *gRange; |
| TGNumberEntry *gSoftwareTrigger; |
| TGNumberEntry *gTriggerChannel; |
| TGNumberEntry *gSamplingFrequency; |
| TGNumberEntry *gTriggerDelay; |
| const char gParNames[30][30]={"Events:","EventNo:","Channel Mask:","Range:", "SwTrg", "TriggerChannel:","Sampling Freq.:","TRG Delay:" }; |
| TGNumberFormat::EStyle gParStyle[10] = { |
| TGNumberFormat::kNESInteger , |
| TGNumberFormat::kNESInteger, |
| TGNumberFormat::kNESInteger , |
| TGNumberFormat::kNESReal, |
| TGNumberFormat::kNESInteger, |
| TGNumberFormat::kNESInteger, |
| TGNumberFormat::kNESInteger, |
| TGNumberFormat::kNESReal |
| }; |
| TGNumberEntry *gParameters[10]; |
| TRootEmbeddedCanvas *gCanvas; |
| #define MAXCH 32 |
| TH1F* gHisto[MAXCH]; |
| //daq * gDaq; |
| #define WINDOW_NAME "Praktikum IV MAPMT PET" |
| //---------------------------------------------------- |
| int UIRDimming(int state){ |
| switch (state) { |
| case 0: |
| gTextButton[0]->SetEnabled(0); |
| gTextButton[1]->SetEnabled(1); |
| gTextButton[2]->SetEnabled(0); |
| break; |
| case 1: |
| gTextButton[0]->SetEnabled(0); |
| gTextButton[1]->SetEnabled(0); |
| gTextButton[2]->SetEnabled(1); |
| break; |
| case 2: |
| gTextButton[0]->SetEnabled(1); |
| gTextButton[1]->SetEnabled(1); |
| gTextButton[2]->SetEnabled(0); |
| break; |
| default: |
| break; |
| } |
| return 0; |
| } |
| int fDebug; |
| void GetDebug(){ |
| if ( gDebugButton->IsOn() ) fDebug=1; |
| else fDebug=0; |
| } |
| int GetTime(char *x){ |
| time_t rawtime; |
| struct tm * timeinfo; |
| time ( &rawtime ); |
| timeinfo = localtime ( &rawtime ); |
| sprintf(x,"%s",asctime (timeinfo)); |
| int len=strlen(x); |
| if (len) x[len-1]=0; |
| return 0; |
| } |
| void MyTimer(){ |
| char cmd[100]; |
| GetTime(cmd); |
| if (gTimeDisplay) gTimeDisplay->SetText(cmd); |
| /* Canvas ni thread safe |
| if (gCanvas){ |
| gCanvas->GetCanvas()->Modified(); |
| gCanvas->GetCanvas()->Update(); |
| } |
| */ |
| } |
| //---------------------------------------------------- |
| // thread function |
| int gStop=0; |
| #define BSIZE 10000 |
| unsigned int gBuf[BSIZE]; |
| void *MyThread(void *ptr) |
| { |
| TThread::Printf("Start of MyThread %x \n" ,(int *)ptr); |
| // odpremo datoteko za pisanje |
| char fname[128]; |
| sprintf(fname,"%s.dat",gFilename->GetText()); |
| FILE *fp=fopen(fname,"w"); |
| int neve = (int) gMaxEve->GetNumber(); |
| int hdr[4]={1}; |
| //if (gDaq) gDaq->fStop=0; |
| // zajem zeljenega kolicine podatkov |
| for (int n=0;n<neve;n++){ |
| int nb=0; |
| /* |
| if (!gDaq) break; |
| nb = gDaq->event(gBuf,BSIZE); |
| if (gDaq->fStop) break; |
| */ |
| if (nb<0){ |
| n--; |
| continue; |
| } |
| // zapis v datoteko |
| hdr[1]=nb+4*sizeof(int); |
| hdr[2]=time(NULL); |
| hdr[3]=n; |
| fwrite(hdr, sizeof(int),4 , fp); |
| fwrite(gBuf, sizeof(int),nb, fp); |
| // napolni histograme |
| //***************** |
| unsigned int *data= gBuf; |
| int evsize=0; |
| int events=0; |
| int ib=1,count=0; |
| events = data[0]; |
| evsize = data[1]&0xffff; |
| if (evsize<2){ |
| n--; |
| continue; |
| } |
| const unsigned int END_MARKER=0xFAF5; |
| if (fDebug) printf("nb=%d Event:%d events=%d EvSize:%d\n",nb, n, events, evsize); |
| for (int i=0;i<evsize;i++) { |
| //if (fDebug) printf("%d\t%08x\n", ib, data[ib]); |
| if (data[ib]== END_MARKER) break; |
| if (ib%2==0) { |
| unsigned short word1 =data[ib ]&0xFFFF; |
| unsigned short word2 =data[ib+1]&0xFFFF; |
| unsigned short tdc = word1; |
| unsigned short ch = (word2 >> 1 ) &0x1F; |
| unsigned short edge = word2 & 0x1; |
| unsigned short q = (word2 >> 8) &0x1; |
| unsigned short x = (word2 >> 9) &0x1; |
| TThread::Lock(); |
| if (edge && ch < MAXCH) gHisto[ch]->Fill(tdc); |
| TThread::UnLock(); |
| if (fDebug) TThread::Printf("%d. [ch=%2d] edge=%d data=%d q=%d x=%d\n",count,ch,edge,tdc, q, x); |
| count++; |
| } |
| ib++; |
| } |
| if (data[evsize+1]!=END_MARKER) printf("Error! END_MARKER not found\n"); |
| //***************** |
| gNeve->SetNumber(n); |
| } |
| fclose(fp); |
| UIRDimming(2); |
| TThread::Printf("End of MyThread neve=%d\n",neve); |
| return 0; |
| } |
| int save2ascii(){ |
| if (!gHisto[0]) return 0; |
| char fname[128]; |
| sprintf(fname,"%s.txt",gFilename->GetText()); |
| FILE *fp= fopen(fname, "w"); |
| fprintf(fp, "%s\n",WINDOW_NAME); |
| char cmd[128]; |
| GetTime(cmd); |
| fprintf(fp, "Shranjeno: %s\n\n", cmd ); |
| fprintf(fp, "Kanal hid=") ; |
| for (int j=0;j<MAXCH;j++) fprintf(fp, "%d\t",j); |
| fprintf(fp, "\n-------------------------------------------------\n"); |
| for (int i=0;i<gHisto[0]->GetNbinsX();i++){ |
| fprintf(fp, "%d\t",i); |
| for (int j=0;j<MAXCH;j++) fprintf(fp, "%d\t",(int) gHisto[j]->GetBinContent(i+1)); |
| fprintf(fp, "\n"); |
| } |
| fclose(fp); |
| printf("Rezultati meritev so zapisani v datoteki %s\n",fname); |
| return 0; |
| } |
| void MyEventHandler(int i){ |
| static TTimer * tmr = new TTimer(1000, kFALSE); |
| UIRDimming(i); |
| TThread *fThread; |
| switch (i) { |
| case 0: // Init |
| //gDaq->init(); |
| break; |
| case 1: // Start |
| fThread = new TThread(MyThread,(void*)0); |
| fThread->Run(); |
| tmr->SetCommand("MyTimer()"); |
| tmr->TurnOn(); |
| tmr->Start(1000, kFALSE); // 1 second single-shot |
| break; |
| case 2: // Stop |
| //gDaq->fStop=1; |
| tmr->Stop(); |
| tmr->TurnOff(); |
| break; |
| case 3: // ReDraw |
| gCanvas->GetCanvas()->Modified(); |
| gCanvas->GetCanvas()->Update(); |
| break; |
| case 4: // Clear |
| for (int j=0;j<MAXCH;j++) if (gHisto[j]) gHisto[j]->Reset(); |
| break; |
| case 5: // Save |
| save2ascii(); |
| break; |
| case 6: // Print |
| gCanvas->GetCanvas()->SaveAs("zivljenjski_cas_mionov.pdf"); |
| break; |
| case 7: // exit |
| gApplication->Terminate(0); |
| break; |
| } |
| } |
| int Redraw(long val=0){ |
| unsigned int ch= (unsigned int)(gCh->GetNumber()); |
| if (ch<MAXCH && gHisto[ch]) { |
| gCanvas->GetCanvas()->cd(); |
| gHisto[ch]->Draw(); |
| gCanvas->GetCanvas()->Modified(); |
| gCanvas->GetCanvas()->Update(); |
| } else { |
| if (gCh->GetNumber()>=MAXCH) gCh->SetNumber(MAXCH-1); |
| if (gCh->GetNumber()< 0) gCh->SetNumber(0); |
| } |
| return 0; |
| } |
| //---------------------------------------------------- |
| int gui(){ |
| for (int i=0;i<MAXCH;i++){ |
| char hname[50]; |
| sprintf(hname,"TDC Ch. %d;TDC;N",i); |
| char hn[50]; |
| sprintf(hn,"ch%d",i); |
| gHisto[i] = new TH1F(hn,hname,128,-0.5,1024*8-0.5); |
| } |
| //gDaq= new daq(); |
| fMain = new TGMainFrame(0,800,800); |
| TGHorizontalFrame *fH=new TGHorizontalFrame(fMain,800,400); |
| //------------------------------------------------------------ |
| TGLayoutHints *f0= new TGLayoutHints(kLHintsLeft | kLHintsTop,2,2,2,2); |
| TGLayoutHints *layout2= new TGLayoutHints(kLHintsLeft | kLHintsTop,20,20,20,20); |
| // gumbi |
| int nbut=8; |
| const char *names[10]={"Init","Start","Stop","Refresh","Clear","Export to ASCII", "Print" , "Exit"}; |
| for (int i=0;i<nbut;i++){ |
| gTextButton[i]= new TGTextButton(fH, names[i]); |
| gTextButton[i]->SetTextJustify(36); |
| gTextButton[i]->SetMargins(0,0,0,0); |
| gTextButton[i]->SetWrapLength(-1); |
| gTextButton[i]->ChangeOptions(gTextButton[i]->GetOptions() | kFixedWidth); // | kFixedSize |
| gTextButton[i]->Resize(100,gTextButton[i]->GetDefaultHeight()); |
| fH->AddFrame(gTextButton[i], f0); |
| char cmd[50]; |
| sprintf(cmd,"MyEventHandler(=%d)",i); |
| TQObject::Connect(gTextButton[i],"Clicked()",0,0,cmd); |
| } |
| gDebugButton = new TGCheckButton( fH,"Debug"); |
| gDebugButton->Resize(50,22); |
| TQObject::Connect(gDebugButton,"Clicked()", 0, 0 , "GetDebug()"); |
| gDebugButton->SetState(kButtonDown); |
| fH->AddFrame(gDebugButton, f0); |
| fMain->AddFrame(fH , f0); |
| TGHorizontalFrame *fH1=new TGHorizontalFrame(fMain,800,400); |
| //--------------------------------------------------------- |
| // ura |
| TGLabel *lab1; |
| fH=new TGHorizontalFrame(fH1,800,200); |
| lab1 = new TGLabel( fH ,"Ura:"); |
| fH->AddFrame(lab1, f0); |
| gTimeDisplay = new TGTextEntry( fH,""); |
| gTimeDisplay->Resize(200,22); |
| fH->AddFrame(gTimeDisplay, f0); |
| fH1->AddFrame(fH , f0); |
| //--------------------------------------------------------- |
| // inputi |
| fH=new TGHorizontalFrame(fH1,800,200); |
| lab1 = new TGLabel( fH ,"Filename:"); |
| fH->AddFrame(lab1, f0); |
| gFilename = new TGTextEntry( fH,"tmp"); |
| gFilename->Resize(200,22); |
| fH->AddFrame(gFilename, f0); |
| fH1->AddFrame(fH , f0); |
| //--------------------------------------------------------- |
| fH=new TGHorizontalFrame(fH1,800,200); |
| lab1 = new TGLabel( fH ,"Events:"); |
| fH->AddFrame(lab1, f0); |
| gMaxEve = new TGNumberEntry( fH,10000); |
| gMaxEve->Resize(100,22); |
| fH->AddFrame(gMaxEve, f0); |
| fH1->AddFrame(fH , f0); |
| //--------------------------------------------------------- |
| fH=new TGHorizontalFrame(fH1,800,200); |
| lab1 = new TGLabel( fH ,"Event no:"); |
| fH->AddFrame(lab1, f0); |
| gNeve = new TGNumberEntry( fH,0); |
| gNeve->Resize(100,22); |
| fH->AddFrame(gNeve, f0); |
| fH1->AddFrame(fH , f0); |
| //--------------------------------------------------------- |
| fMain->AddFrame(fH1 , f0); |
| TGVerticalFrame *fV=new TGVerticalFrame(fMain,800,200); |
| nbut = 8; |
| for (int i=0;i<nbut;i++){ |
| fH=new TGHorizontalFrame(fV,800,200); |
| lab1 = new TGLabel( fH ,gParNames[i]); |
| lab1->Resize(100,22); |
| fH->AddFrame(lab1, f0); |
| gParameters[i] = new TGNumberEntry( fH,0,5,i, gParStyle[i] ); |
| gParameters[i]->Resize(100,22); |
| fH->AddFrame(gParameters[i] , f0); |
| fV->AddFrame(fH , f0); |
| } |
| fMain->AddFrame(fV , f0); |
| //--------------------------------------------------------- |
| // canvas |
| fH=new TGHorizontalFrame(fMain,800,200); |
| gCanvas = new TRootEmbeddedCanvas ("gCanvas",fH,800,400); |
| fH->AddFrame(gCanvas, f0); |
| fMain->AddFrame(fH , f0); |
| //------------------------------------------------------------ |
| fH=new TGHorizontalFrame(fMain,800,200); |
| lab1 = new TGLabel( fH ,"Ch. Number(0..3):"); |
| fH->AddFrame(lab1, f0); |
| gCh = new TGNumberEntry( fH,0); |
| fH->AddFrame(gCh, f0); |
| TQObject::Connect(gCh,"ValueSet(Long_t)",0,0,"Redraw(Long_t )"); |
| fMain->AddFrame(fH , f0); |
| //------------------------------------------------------------ |
| fMain->SetWindowName(WINDOW_NAME); |
| fMain->MapSubwindows(); |
| fMain->Resize(fMain->GetDefaultSize()); |
| fMain->MapWindow(); |
| Redraw(); |
| GetDebug(); |
| return 0; |
| } |
| /cvi/instr/drsctrl/libusb-1.0/libusb.h |
|---|
| 0,0 → 1,1443 |
| /* |
| * Public libusb header file |
| * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org> |
| * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| #ifndef LIBUSB_H |
| #define LIBUSB_H |
| #ifdef _MSC_VER |
| /* on MS environments, the inline keyword is available in C++ only */ |
| #define inline __inline |
| /* ssize_t is also not available (copy/paste from MinGW) */ |
| #ifndef _SSIZE_T_DEFINED |
| #define _SSIZE_T_DEFINED |
| #undef ssize_t |
| #ifdef _WIN64 |
| typedef __int64 ssize_t; |
| #else |
| typedef int ssize_t; |
| #endif /* _WIN64 */ |
| #endif /* _SSIZE_T_DEFINED */ |
| #endif /* _MSC_VER */ |
| /* stdint.h is also not usually available on MS */ |
| #if defined(_MSC_VER) && (_MSC_VER < 1600) && (!defined(_STDINT)) && (!defined(_STDINT_H)) |
| typedef unsigned __int8 uint8_t; |
| typedef unsigned __int16 uint16_t; |
| typedef unsigned __int32 uint32_t; |
| #else |
| #include <stdint.h> |
| #endif |
| #include <sys/types.h> |
| #include <time.h> |
| #include <limits.h> |
| #if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__) |
| #include <sys/time.h> |
| #endif |
| /* 'interface' might be defined as a macro on Windows, so we need to |
| * undefine it so as not to break the current libusb API, because |
| * libusb_config_descriptor has an 'interface' member |
| * As this can be problematic if you include windows.h after libusb.h |
| * in your sources, we force windows.h to be included first. */ |
| #if defined(_WIN32) || defined(__CYGWIN__) |
| #include <windows.h> |
| #if defined(interface) |
| #undef interface |
| #endif |
| #endif |
| /** \def LIBUSB_CALL |
| * \ingroup misc |
| * libusb's Windows calling convention. |
| * |
| * Under Windows, the selection of available compilers and configurations |
| * means that, unlike other platforms, there is not <em>one true calling |
| * convention</em> (calling convention: the manner in which parameters are |
| * passed to funcions in the generated assembly code). |
| * |
| * Matching the Windows API itself, libusb uses the WINAPI convention (which |
| * translates to the <tt>stdcall</tt> convention) and guarantees that the |
| * library is compiled in this way. The public header file also includes |
| * appropriate annotations so that your own software will use the right |
| * convention, even if another convention is being used by default within |
| * your codebase. |
| * |
| * The one consideration that you must apply in your software is to mark |
| * all functions which you use as libusb callbacks with this LIBUSB_CALL |
| * annotation, so that they too get compiled for the correct calling |
| * convention. |
| * |
| * On non-Windows operating systems, this macro is defined as nothing. This |
| * means that you can apply it to your code without worrying about |
| * cross-platform compatibility. |
| */ |
| /* LIBUSB_CALL must be defined on both definition and declaration of libusb |
| * functions. You'd think that declaration would be enough, but cygwin will |
| * complain about conflicting types unless both are marked this way. |
| * The placement of this macro is important too; it must appear after the |
| * return type, before the function name. See internal documentation for |
| * API_EXPORTED. |
| */ |
| #if defined(_WIN32) || defined(__CYGWIN__) |
| #define LIBUSB_CALL WINAPI |
| #else |
| #define LIBUSB_CALL |
| #endif |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| /** \def libusb_cpu_to_le16 |
| * \ingroup misc |
| * Convert a 16-bit value from host-endian to little-endian format. On |
| * little endian systems, this function does nothing. On big endian systems, |
| * the bytes are swapped. |
| * \param x the host-endian value to convert |
| * \returns the value in little-endian byte order |
| */ |
| static inline uint16_t libusb_cpu_to_le16(const uint16_t x) |
| { |
| union { |
| uint8_t b8[2]; |
| uint16_t b16; |
| } _tmp; |
| _tmp.b8[1] = x >> 8; |
| _tmp.b8[0] = x & 0xff; |
| return _tmp.b16; |
| } |
| /** \def libusb_le16_to_cpu |
| * \ingroup misc |
| * Convert a 16-bit value from little-endian to host-endian format. On |
| * little endian systems, this function does nothing. On big endian systems, |
| * the bytes are swapped. |
| * \param x the little-endian value to convert |
| * \returns the value in host-endian byte order |
| */ |
| #define libusb_le16_to_cpu libusb_cpu_to_le16 |
| /* standard USB stuff */ |
| /** \ingroup desc |
| * Device and/or Interface Class codes */ |
| enum libusb_class_code { |
| /** In the context of a \ref libusb_device_descriptor "device descriptor", |
| * this bDeviceClass value indicates that each interface specifies its |
| * own class information and all interfaces operate independently. |
| */ |
| LIBUSB_CLASS_PER_INTERFACE = 0, |
| /** Audio class */ |
| LIBUSB_CLASS_AUDIO = 1, |
| /** Communications class */ |
| LIBUSB_CLASS_COMM = 2, |
| /** Human Interface Device class */ |
| LIBUSB_CLASS_HID = 3, |
| /** Physical */ |
| LIBUSB_CLASS_PHYSICAL = 5, |
| /** Printer class */ |
| LIBUSB_CLASS_PRINTER = 7, |
| /** Image class */ |
| LIBUSB_CLASS_PTP = 6, /* legacy name from libusb-0.1 usb.h */ |
| LIBUSB_CLASS_IMAGE = 6, |
| /** Mass storage class */ |
| LIBUSB_CLASS_MASS_STORAGE = 8, |
| /** Hub class */ |
| LIBUSB_CLASS_HUB = 9, |
| /** Data class */ |
| LIBUSB_CLASS_DATA = 10, |
| /** Smart Card */ |
| LIBUSB_CLASS_SMART_CARD = 0x0b, |
| /** Content Security */ |
| LIBUSB_CLASS_CONTENT_SECURITY = 0x0d, |
| /** Video */ |
| LIBUSB_CLASS_VIDEO = 0x0e, |
| /** Personal Healthcare */ |
| LIBUSB_CLASS_PERSONAL_HEALTHCARE = 0x0f, |
| /** Diagnostic Device */ |
| LIBUSB_CLASS_DIAGNOSTIC_DEVICE = 0xdc, |
| /** Wireless class */ |
| LIBUSB_CLASS_WIRELESS = 0xe0, |
| /** Application class */ |
| LIBUSB_CLASS_APPLICATION = 0xfe, |
| /** Class is vendor-specific */ |
| LIBUSB_CLASS_VENDOR_SPEC = 0xff |
| }; |
| /** \ingroup desc |
| * Descriptor types as defined by the USB specification. */ |
| enum libusb_descriptor_type { |
| /** Device descriptor. See libusb_device_descriptor. */ |
| LIBUSB_DT_DEVICE = 0x01, |
| /** Configuration descriptor. See libusb_config_descriptor. */ |
| LIBUSB_DT_CONFIG = 0x02, |
| /** String descriptor */ |
| LIBUSB_DT_STRING = 0x03, |
| /** Interface descriptor. See libusb_interface_descriptor. */ |
| LIBUSB_DT_INTERFACE = 0x04, |
| /** Endpoint descriptor. See libusb_endpoint_descriptor. */ |
| LIBUSB_DT_ENDPOINT = 0x05, |
| /** HID descriptor */ |
| LIBUSB_DT_HID = 0x21, |
| /** HID report descriptor */ |
| LIBUSB_DT_REPORT = 0x22, |
| /** Physical descriptor */ |
| LIBUSB_DT_PHYSICAL = 0x23, |
| /** Hub descriptor */ |
| LIBUSB_DT_HUB = 0x29, |
| }; |
| /* Descriptor sizes per descriptor type */ |
| #define LIBUSB_DT_DEVICE_SIZE 18 |
| #define LIBUSB_DT_CONFIG_SIZE 9 |
| #define LIBUSB_DT_INTERFACE_SIZE 9 |
| #define LIBUSB_DT_ENDPOINT_SIZE 7 |
| #define LIBUSB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ |
| #define LIBUSB_DT_HUB_NONVAR_SIZE 7 |
| #define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */ |
| #define LIBUSB_ENDPOINT_DIR_MASK 0x80 |
| /** \ingroup desc |
| * Endpoint direction. Values for bit 7 of the |
| * \ref libusb_endpoint_descriptor::bEndpointAddress "endpoint address" scheme. |
| */ |
| enum libusb_endpoint_direction { |
| /** In: device-to-host */ |
| LIBUSB_ENDPOINT_IN = 0x80, |
| /** Out: host-to-device */ |
| LIBUSB_ENDPOINT_OUT = 0x00 |
| }; |
| #define LIBUSB_TRANSFER_TYPE_MASK 0x03 /* in bmAttributes */ |
| /** \ingroup desc |
| * Endpoint transfer type. Values for bits 0:1 of the |
| * \ref libusb_endpoint_descriptor::bmAttributes "endpoint attributes" field. |
| */ |
| enum libusb_transfer_type { |
| /** Control endpoint */ |
| LIBUSB_TRANSFER_TYPE_CONTROL = 0, |
| /** Isochronous endpoint */ |
| LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1, |
| /** Bulk endpoint */ |
| LIBUSB_TRANSFER_TYPE_BULK = 2, |
| /** Interrupt endpoint */ |
| LIBUSB_TRANSFER_TYPE_INTERRUPT = 3 |
| }; |
| /** \ingroup misc |
| * Standard requests, as defined in table 9-3 of the USB2 specifications */ |
| enum libusb_standard_request { |
| /** Request status of the specific recipient */ |
| LIBUSB_REQUEST_GET_STATUS = 0x00, |
| /** Clear or disable a specific feature */ |
| LIBUSB_REQUEST_CLEAR_FEATURE = 0x01, |
| /* 0x02 is reserved */ |
| /** Set or enable a specific feature */ |
| LIBUSB_REQUEST_SET_FEATURE = 0x03, |
| /* 0x04 is reserved */ |
| /** Set device address for all future accesses */ |
| LIBUSB_REQUEST_SET_ADDRESS = 0x05, |
| /** Get the specified descriptor */ |
| LIBUSB_REQUEST_GET_DESCRIPTOR = 0x06, |
| /** Used to update existing descriptors or add new descriptors */ |
| LIBUSB_REQUEST_SET_DESCRIPTOR = 0x07, |
| /** Get the current device configuration value */ |
| LIBUSB_REQUEST_GET_CONFIGURATION = 0x08, |
| /** Set device configuration */ |
| LIBUSB_REQUEST_SET_CONFIGURATION = 0x09, |
| /** Return the selected alternate setting for the specified interface */ |
| LIBUSB_REQUEST_GET_INTERFACE = 0x0A, |
| /** Select an alternate interface for the specified interface */ |
| LIBUSB_REQUEST_SET_INTERFACE = 0x0B, |
| /** Set then report an endpoint's synchronization frame */ |
| LIBUSB_REQUEST_SYNCH_FRAME = 0x0C, |
| }; |
| /** \ingroup misc |
| * Request type bits of the |
| * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control |
| * transfers. */ |
| enum libusb_request_type { |
| /** Standard */ |
| LIBUSB_REQUEST_TYPE_STANDARD = (0x00 << 5), |
| /** Class */ |
| LIBUSB_REQUEST_TYPE_CLASS = (0x01 << 5), |
| /** Vendor */ |
| LIBUSB_REQUEST_TYPE_VENDOR = (0x02 << 5), |
| /** Reserved */ |
| LIBUSB_REQUEST_TYPE_RESERVED = (0x03 << 5) |
| }; |
| /** \ingroup misc |
| * Recipient bits of the |
| * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control |
| * transfers. Values 4 through 31 are reserved. */ |
| enum libusb_request_recipient { |
| /** Device */ |
| LIBUSB_RECIPIENT_DEVICE = 0x00, |
| /** Interface */ |
| LIBUSB_RECIPIENT_INTERFACE = 0x01, |
| /** Endpoint */ |
| LIBUSB_RECIPIENT_ENDPOINT = 0x02, |
| /** Other */ |
| LIBUSB_RECIPIENT_OTHER = 0x03, |
| }; |
| #define LIBUSB_ISO_SYNC_TYPE_MASK 0x0C |
| /** \ingroup desc |
| * Synchronization type for isochronous endpoints. Values for bits 2:3 of the |
| * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in |
| * libusb_endpoint_descriptor. |
| */ |
| enum libusb_iso_sync_type { |
| /** No synchronization */ |
| LIBUSB_ISO_SYNC_TYPE_NONE = 0, |
| /** Asynchronous */ |
| LIBUSB_ISO_SYNC_TYPE_ASYNC = 1, |
| /** Adaptive */ |
| LIBUSB_ISO_SYNC_TYPE_ADAPTIVE = 2, |
| /** Synchronous */ |
| LIBUSB_ISO_SYNC_TYPE_SYNC = 3 |
| }; |
| #define LIBUSB_ISO_USAGE_TYPE_MASK 0x30 |
| /** \ingroup desc |
| * Usage type for isochronous endpoints. Values for bits 4:5 of the |
| * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in |
| * libusb_endpoint_descriptor. |
| */ |
| enum libusb_iso_usage_type { |
| /** Data endpoint */ |
| LIBUSB_ISO_USAGE_TYPE_DATA = 0, |
| /** Feedback endpoint */ |
| LIBUSB_ISO_USAGE_TYPE_FEEDBACK = 1, |
| /** Implicit feedback Data endpoint */ |
| LIBUSB_ISO_USAGE_TYPE_IMPLICIT = 2, |
| }; |
| /** \ingroup desc |
| * A structure representing the standard USB device descriptor. This |
| * descriptor is documented in section 9.6.1 of the USB 2.0 specification. |
| * All multiple-byte fields are represented in host-endian format. |
| */ |
| struct libusb_device_descriptor { |
| /** Size of this descriptor (in bytes) */ |
| uint8_t bLength; |
| /** Descriptor type. Will have value |
| * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE LIBUSB_DT_DEVICE in this |
| * context. */ |
| uint8_t bDescriptorType; |
| /** USB specification release number in binary-coded decimal. A value of |
| * 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1, etc. */ |
| uint16_t bcdUSB; |
| /** USB-IF class code for the device. See \ref libusb_class_code. */ |
| uint8_t bDeviceClass; |
| /** USB-IF subclass code for the device, qualified by the bDeviceClass |
| * value */ |
| uint8_t bDeviceSubClass; |
| /** USB-IF protocol code for the device, qualified by the bDeviceClass and |
| * bDeviceSubClass values */ |
| uint8_t bDeviceProtocol; |
| /** Maximum packet size for endpoint 0 */ |
| uint8_t bMaxPacketSize0; |
| /** USB-IF vendor ID */ |
| uint16_t idVendor; |
| /** USB-IF product ID */ |
| uint16_t idProduct; |
| /** Device release number in binary-coded decimal */ |
| uint16_t bcdDevice; |
| /** Index of string descriptor describing manufacturer */ |
| uint8_t iManufacturer; |
| /** Index of string descriptor describing product */ |
| uint8_t iProduct; |
| /** Index of string descriptor containing device serial number */ |
| uint8_t iSerialNumber; |
| /** Number of possible configurations */ |
| uint8_t bNumConfigurations; |
| }; |
| /** \ingroup desc |
| * A structure representing the standard USB endpoint descriptor. This |
| * descriptor is documented in section 9.6.3 of the USB 2.0 specification. |
| * All multiple-byte fields are represented in host-endian format. |
| */ |
| struct libusb_endpoint_descriptor { |
| /** Size of this descriptor (in bytes) */ |
| uint8_t bLength; |
| /** Descriptor type. Will have value |
| * \ref libusb_descriptor_type::LIBUSB_DT_ENDPOINT LIBUSB_DT_ENDPOINT in |
| * this context. */ |
| uint8_t bDescriptorType; |
| /** The address of the endpoint described by this descriptor. Bits 0:3 are |
| * the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction, |
| * see \ref libusb_endpoint_direction. |
| */ |
| uint8_t bEndpointAddress; |
| /** Attributes which apply to the endpoint when it is configured using |
| * the bConfigurationValue. Bits 0:1 determine the transfer type and |
| * correspond to \ref libusb_transfer_type. Bits 2:3 are only used for |
| * isochronous endpoints and correspond to \ref libusb_iso_sync_type. |
| * Bits 4:5 are also only used for isochronous endpoints and correspond to |
| * \ref libusb_iso_usage_type. Bits 6:7 are reserved. |
| */ |
| uint8_t bmAttributes; |
| /** Maximum packet size this endpoint is capable of sending/receiving. */ |
| uint16_t wMaxPacketSize; |
| /** Interval for polling endpoint for data transfers. */ |
| uint8_t bInterval; |
| /** For audio devices only: the rate at which synchronization feedback |
| * is provided. */ |
| uint8_t bRefresh; |
| /** For audio devices only: the address if the synch endpoint */ |
| uint8_t bSynchAddress; |
| /** Extra descriptors. If libusb encounters unknown endpoint descriptors, |
| * it will store them here, should you wish to parse them. */ |
| const unsigned char *extra; |
| /** Length of the extra descriptors, in bytes. */ |
| int extra_length; |
| }; |
| /** \ingroup desc |
| * A structure representing the standard USB interface descriptor. This |
| * descriptor is documented in section 9.6.5 of the USB 2.0 specification. |
| * All multiple-byte fields are represented in host-endian format. |
| */ |
| struct libusb_interface_descriptor { |
| /** Size of this descriptor (in bytes) */ |
| uint8_t bLength; |
| /** Descriptor type. Will have value |
| * \ref libusb_descriptor_type::LIBUSB_DT_INTERFACE LIBUSB_DT_INTERFACE |
| * in this context. */ |
| uint8_t bDescriptorType; |
| /** Number of this interface */ |
| uint8_t bInterfaceNumber; |
| /** Value used to select this alternate setting for this interface */ |
| uint8_t bAlternateSetting; |
| /** Number of endpoints used by this interface (excluding the control |
| * endpoint). */ |
| uint8_t bNumEndpoints; |
| /** USB-IF class code for this interface. See \ref libusb_class_code. */ |
| uint8_t bInterfaceClass; |
| /** USB-IF subclass code for this interface, qualified by the |
| * bInterfaceClass value */ |
| uint8_t bInterfaceSubClass; |
| /** USB-IF protocol code for this interface, qualified by the |
| * bInterfaceClass and bInterfaceSubClass values */ |
| uint8_t bInterfaceProtocol; |
| /** Index of string descriptor describing this interface */ |
| uint8_t iInterface; |
| /** Array of endpoint descriptors. This length of this array is determined |
| * by the bNumEndpoints field. */ |
| const struct libusb_endpoint_descriptor *endpoint; |
| /** Extra descriptors. If libusb encounters unknown interface descriptors, |
| * it will store them here, should you wish to parse them. */ |
| const unsigned char *extra; |
| /** Length of the extra descriptors, in bytes. */ |
| int extra_length; |
| }; |
| /** \ingroup desc |
| * A collection of alternate settings for a particular USB interface. |
| */ |
| struct libusb_interface { |
| /** Array of interface descriptors. The length of this array is determined |
| * by the num_altsetting field. */ |
| const struct libusb_interface_descriptor *altsetting; |
| /** The number of alternate settings that belong to this interface */ |
| int num_altsetting; |
| }; |
| /** \ingroup desc |
| * A structure representing the standard USB configuration descriptor. This |
| * descriptor is documented in section 9.6.3 of the USB 2.0 specification. |
| * All multiple-byte fields are represented in host-endian format. |
| */ |
| struct libusb_config_descriptor { |
| /** Size of this descriptor (in bytes) */ |
| uint8_t bLength; |
| /** Descriptor type. Will have value |
| * \ref libusb_descriptor_type::LIBUSB_DT_CONFIG LIBUSB_DT_CONFIG |
| * in this context. */ |
| uint8_t bDescriptorType; |
| /** Total length of data returned for this configuration */ |
| uint16_t wTotalLength; |
| /** Number of interfaces supported by this configuration */ |
| uint8_t bNumInterfaces; |
| /** Identifier value for this configuration */ |
| uint8_t bConfigurationValue; |
| /** Index of string descriptor describing this configuration */ |
| uint8_t iConfiguration; |
| /** Configuration characteristics */ |
| uint8_t bmAttributes; |
| /** Maximum power consumption of the USB device from this bus in this |
| * configuration when the device is fully opreation. Expressed in units |
| * of 2 mA. */ |
| uint8_t MaxPower; |
| /** Array of interfaces supported by this configuration. The length of |
| * this array is determined by the bNumInterfaces field. */ |
| const struct libusb_interface *interface; |
| /** Extra descriptors. If libusb encounters unknown configuration |
| * descriptors, it will store them here, should you wish to parse them. */ |
| const unsigned char *extra; |
| /** Length of the extra descriptors, in bytes. */ |
| int extra_length; |
| }; |
| /** \ingroup asyncio |
| * Setup packet for control transfers. */ |
| struct libusb_control_setup { |
| /** Request type. Bits 0:4 determine recipient, see |
| * \ref libusb_request_recipient. Bits 5:6 determine type, see |
| * \ref libusb_request_type. Bit 7 determines data transfer direction, see |
| * \ref libusb_endpoint_direction. |
| */ |
| uint8_t bmRequestType; |
| /** Request. If the type bits of bmRequestType are equal to |
| * \ref libusb_request_type::LIBUSB_REQUEST_TYPE_STANDARD |
| * "LIBUSB_REQUEST_TYPE_STANDARD" then this field refers to |
| * \ref libusb_standard_request. For other cases, use of this field is |
| * application-specific. */ |
| uint8_t bRequest; |
| /** Value. Varies according to request */ |
| uint16_t wValue; |
| /** Index. Varies according to request, typically used to pass an index |
| * or offset */ |
| uint16_t wIndex; |
| /** Number of bytes to transfer */ |
| uint16_t wLength; |
| }; |
| #define LIBUSB_CONTROL_SETUP_SIZE (sizeof(struct libusb_control_setup)) |
| /* libusb */ |
| struct libusb_context; |
| struct libusb_device; |
| struct libusb_device_handle; |
| /** \ingroup lib |
| * Structure representing the libusb version. |
| */ |
| struct libusb_version { |
| /** Library major version. */ |
| const uint16_t major; |
| /** Library minor version. */ |
| const uint16_t minor; |
| /** Library micro version. */ |
| const uint16_t micro; |
| /** Library nano version. This field is only nonzero on Windows. */ |
| const uint16_t nano; |
| /** Library release candidate suffix string, e.g. "-rc4". */ |
| const char *rc; |
| /** Output of `git describe --tags` at library build time. */ |
| const char *describe; |
| }; |
| /** \ingroup lib |
| * Structure representing a libusb session. The concept of individual libusb |
| * sessions allows for your program to use two libraries (or dynamically |
| * load two modules) which both independently use libusb. This will prevent |
| * interference between the individual libusb users - for example |
| * libusb_set_debug() will not affect the other user of the library, and |
| * libusb_exit() will not destroy resources that the other user is still |
| * using. |
| * |
| * Sessions are created by libusb_init() and destroyed through libusb_exit(). |
| * If your application is guaranteed to only ever include a single libusb |
| * user (i.e. you), you do not have to worry about contexts: pass NULL in |
| * every function call where a context is required. The default context |
| * will be used. |
| * |
| * For more information, see \ref contexts. |
| */ |
| typedef struct libusb_context libusb_context; |
| /** \ingroup dev |
| * Structure representing a USB device detected on the system. This is an |
| * opaque type for which you are only ever provided with a pointer, usually |
| * originating from libusb_get_device_list(). |
| * |
| * Certain operations can be performed on a device, but in order to do any |
| * I/O you will have to first obtain a device handle using libusb_open(). |
| * |
| * Devices are reference counted with libusb_device_ref() and |
| * libusb_device_unref(), and are freed when the reference count reaches 0. |
| * New devices presented by libusb_get_device_list() have a reference count of |
| * 1, and libusb_free_device_list() can optionally decrease the reference count |
| * on all devices in the list. libusb_open() adds another reference which is |
| * later destroyed by libusb_close(). |
| */ |
| typedef struct libusb_device libusb_device; |
| /** \ingroup dev |
| * Structure representing a handle on a USB device. This is an opaque type for |
| * which you are only ever provided with a pointer, usually originating from |
| * libusb_open(). |
| * |
| * A device handle is used to perform I/O and other operations. When finished |
| * with a device handle, you should call libusb_close(). |
| */ |
| typedef struct libusb_device_handle libusb_device_handle; |
| /** \ingroup dev |
| * Speed codes. Indicates the speed at which the device is operating. |
| */ |
| enum libusb_speed { |
| /** The OS doesn't report or know the device speed. */ |
| LIBUSB_SPEED_UNKNOWN = 0, |
| /** The device is operating at low speed (1.5MBit/s). */ |
| LIBUSB_SPEED_LOW = 1, |
| /** The device is operating at full speed (12MBit/s). */ |
| LIBUSB_SPEED_FULL = 2, |
| /** The device is operating at high speed (480MBit/s). */ |
| LIBUSB_SPEED_HIGH = 3, |
| /** The device is operating at super speed (5000MBit/s). */ |
| LIBUSB_SPEED_SUPER = 4, |
| }; |
| /** \ingroup misc |
| * Error codes. Most libusb functions return 0 on success or one of these |
| * codes on failure. |
| * You can call \ref libusb_error_name() to retrieve a string representation |
| * of an error code. |
| */ |
| enum libusb_error { |
| /** Success (no error) */ |
| LIBUSB_SUCCESS = 0, |
| /** Input/output error */ |
| LIBUSB_ERROR_IO = -1, |
| /** Invalid parameter */ |
| LIBUSB_ERROR_INVALID_PARAM = -2, |
| /** Access denied (insufficient permissions) */ |
| LIBUSB_ERROR_ACCESS = -3, |
| /** No such device (it may have been disconnected) */ |
| LIBUSB_ERROR_NO_DEVICE = -4, |
| /** Entity not found */ |
| LIBUSB_ERROR_NOT_FOUND = -5, |
| /** Resource busy */ |
| LIBUSB_ERROR_BUSY = -6, |
| /** Operation timed out */ |
| LIBUSB_ERROR_TIMEOUT = -7, |
| /** Overflow */ |
| LIBUSB_ERROR_OVERFLOW = -8, |
| /** Pipe error */ |
| LIBUSB_ERROR_PIPE = -9, |
| /** System call interrupted (perhaps due to signal) */ |
| LIBUSB_ERROR_INTERRUPTED = -10, |
| /** Insufficient memory */ |
| LIBUSB_ERROR_NO_MEM = -11, |
| /** Operation not supported or unimplemented on this platform */ |
| LIBUSB_ERROR_NOT_SUPPORTED = -12, |
| /* NB! Remember to update libusb_error_name() |
| when adding new error codes here. */ |
| /** Other error */ |
| LIBUSB_ERROR_OTHER = -99, |
| }; |
| /** \ingroup asyncio |
| * Transfer status codes */ |
| enum libusb_transfer_status { |
| /** Transfer completed without error. Note that this does not indicate |
| * that the entire amount of requested data was transferred. */ |
| LIBUSB_TRANSFER_COMPLETED, |
| /** Transfer failed */ |
| LIBUSB_TRANSFER_ERROR, |
| /** Transfer timed out */ |
| LIBUSB_TRANSFER_TIMED_OUT, |
| /** Transfer was cancelled */ |
| LIBUSB_TRANSFER_CANCELLED, |
| /** For bulk/interrupt endpoints: halt condition detected (endpoint |
| * stalled). For control endpoints: control request not supported. */ |
| LIBUSB_TRANSFER_STALL, |
| /** Device was disconnected */ |
| LIBUSB_TRANSFER_NO_DEVICE, |
| /** Device sent more data than requested */ |
| LIBUSB_TRANSFER_OVERFLOW, |
| }; |
| /** \ingroup asyncio |
| * libusb_transfer.flags values */ |
| enum libusb_transfer_flags { |
| /** Report short frames as errors */ |
| LIBUSB_TRANSFER_SHORT_NOT_OK = 1<<0, |
| /** Automatically free() transfer buffer during libusb_free_transfer() */ |
| LIBUSB_TRANSFER_FREE_BUFFER = 1<<1, |
| /** Automatically call libusb_free_transfer() after callback returns. |
| * If this flag is set, it is illegal to call libusb_free_transfer() |
| * from your transfer callback, as this will result in a double-free |
| * when this flag is acted upon. */ |
| LIBUSB_TRANSFER_FREE_TRANSFER = 1<<2, |
| /** Terminate transfers that are a multiple of the endpoint's |
| * wMaxPacketSize with an extra zero length packet. This is useful |
| * when a device protocol mandates that each logical request is |
| * terminated by an incomplete packet (i.e. the logical requests are |
| * not separated by other means). |
| * |
| * This flag only affects host-to-device transfers to bulk and interrupt |
| * endpoints. In other situations, it is ignored. |
| * |
| * This flag only affects transfers with a length that is a multiple of |
| * the endpoint's wMaxPacketSize. On transfers of other lengths, this |
| * flag has no effect. Therefore, if you are working with a device that |
| * needs a ZLP whenever the end of the logical request falls on a packet |
| * boundary, then it is sensible to set this flag on <em>every</em> |
| * transfer (you do not have to worry about only setting it on transfers |
| * that end on the boundary). |
| * |
| * This flag is currently only supported on Linux. |
| * On other systems, libusb_submit_transfer() will return |
| * LIBUSB_ERROR_NOT_SUPPORTED for every transfer where this flag is set. |
| * |
| * Available since libusb-1.0.9. |
| */ |
| LIBUSB_TRANSFER_ADD_ZERO_PACKET = 1 << 3, |
| }; |
| /** \ingroup asyncio |
| * Isochronous packet descriptor. */ |
| struct libusb_iso_packet_descriptor { |
| /** Length of data to request in this packet */ |
| unsigned int length; |
| /** Amount of data that was actually transferred */ |
| unsigned int actual_length; |
| /** Status code for this packet */ |
| enum libusb_transfer_status status; |
| }; |
| struct libusb_transfer; |
| /** \ingroup asyncio |
| * Asynchronous transfer callback function type. When submitting asynchronous |
| * transfers, you pass a pointer to a callback function of this type via the |
| * \ref libusb_transfer::callback "callback" member of the libusb_transfer |
| * structure. libusb will call this function later, when the transfer has |
| * completed or failed. See \ref asyncio for more information. |
| * \param transfer The libusb_transfer struct the callback function is being |
| * notified about. |
| */ |
| typedef void (LIBUSB_CALL *libusb_transfer_cb_fn)(struct libusb_transfer *transfer); |
| /** \ingroup asyncio |
| * The generic USB transfer structure. The user populates this structure and |
| * then submits it in order to request a transfer. After the transfer has |
| * completed, the library populates the transfer with the results and passes |
| * it back to the user. |
| */ |
| struct libusb_transfer { |
| /** Handle of the device that this transfer will be submitted to */ |
| libusb_device_handle *dev_handle; |
| /** A bitwise OR combination of \ref libusb_transfer_flags. */ |
| uint8_t flags; |
| /** Address of the endpoint where this transfer will be sent. */ |
| unsigned char endpoint; |
| /** Type of the endpoint from \ref libusb_transfer_type */ |
| unsigned char type; |
| /** Timeout for this transfer in millseconds. A value of 0 indicates no |
| * timeout. */ |
| unsigned int timeout; |
| /** The status of the transfer. Read-only, and only for use within |
| * transfer callback function. |
| * |
| * If this is an isochronous transfer, this field may read COMPLETED even |
| * if there were errors in the frames. Use the |
| * \ref libusb_iso_packet_descriptor::status "status" field in each packet |
| * to determine if errors occurred. */ |
| enum libusb_transfer_status status; |
| /** Length of the data buffer */ |
| int length; |
| /** Actual length of data that was transferred. Read-only, and only for |
| * use within transfer callback function. Not valid for isochronous |
| * endpoint transfers. */ |
| int actual_length; |
| /** Callback function. This will be invoked when the transfer completes, |
| * fails, or is cancelled. */ |
| libusb_transfer_cb_fn callback; |
| /** User context data to pass to the callback function. */ |
| void *user_data; |
| /** Data buffer */ |
| unsigned char *buffer; |
| /** Number of isochronous packets. Only used for I/O with isochronous |
| * endpoints. */ |
| int num_iso_packets; |
| /** Isochronous packet descriptors, for isochronous transfers only. */ |
| struct libusb_iso_packet_descriptor iso_packet_desc |
| #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) |
| [] /* valid C99 code */ |
| #else |
| [0] /* non-standard, but usually working code */ |
| #endif |
| ; |
| }; |
| /** \ingroup misc |
| * Capabilities supported by this instance of libusb. Test if the loaded |
| * library supports a given capability by calling |
| * \ref libusb_has_capability(). |
| */ |
| enum libusb_capability { |
| /** The libusb_has_capability() API is available. */ |
| LIBUSB_CAP_HAS_CAPABILITY = 0, |
| }; |
| int LIBUSB_CALL libusb_init(libusb_context **ctx); |
| void LIBUSB_CALL libusb_exit(libusb_context *ctx); |
| void LIBUSB_CALL libusb_set_debug(libusb_context *ctx, int level); |
| const struct libusb_version * LIBUSB_CALL libusb_get_version(void); |
| int LIBUSB_CALL libusb_has_capability(uint32_t capability); |
| const char * LIBUSB_CALL libusb_error_name(int errcode); |
| ssize_t LIBUSB_CALL libusb_get_device_list(libusb_context *ctx, |
| libusb_device ***list); |
| void LIBUSB_CALL libusb_free_device_list(libusb_device **list, |
| int unref_devices); |
| libusb_device * LIBUSB_CALL libusb_ref_device(libusb_device *dev); |
| void LIBUSB_CALL libusb_unref_device(libusb_device *dev); |
| int LIBUSB_CALL libusb_get_configuration(libusb_device_handle *dev, |
| int *config); |
| int LIBUSB_CALL libusb_get_device_descriptor(libusb_device *dev, |
| struct libusb_device_descriptor *desc); |
| int LIBUSB_CALL libusb_get_active_config_descriptor(libusb_device *dev, |
| struct libusb_config_descriptor **config); |
| int LIBUSB_CALL libusb_get_config_descriptor(libusb_device *dev, |
| uint8_t config_index, struct libusb_config_descriptor **config); |
| int LIBUSB_CALL libusb_get_config_descriptor_by_value(libusb_device *dev, |
| uint8_t bConfigurationValue, struct libusb_config_descriptor **config); |
| void LIBUSB_CALL libusb_free_config_descriptor( |
| struct libusb_config_descriptor *config); |
| uint8_t LIBUSB_CALL libusb_get_bus_number(libusb_device *dev); |
| uint8_t LIBUSB_CALL libusb_get_device_address(libusb_device *dev); |
| int LIBUSB_CALL libusb_get_device_speed(libusb_device *dev); |
| int LIBUSB_CALL libusb_get_max_packet_size(libusb_device *dev, |
| unsigned char endpoint); |
| int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev, |
| unsigned char endpoint); |
| int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **handle); |
| void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle); |
| libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle); |
| int LIBUSB_CALL libusb_set_configuration(libusb_device_handle *dev, |
| int configuration); |
| int LIBUSB_CALL libusb_claim_interface(libusb_device_handle *dev, |
| int interface_number); |
| int LIBUSB_CALL libusb_release_interface(libusb_device_handle *dev, |
| int interface_number); |
| libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid( |
| libusb_context *ctx, uint16_t vendor_id, uint16_t product_id); |
| int LIBUSB_CALL libusb_set_interface_alt_setting(libusb_device_handle *dev, |
| int interface_number, int alternate_setting); |
| int LIBUSB_CALL libusb_clear_halt(libusb_device_handle *dev, |
| unsigned char endpoint); |
| int LIBUSB_CALL libusb_reset_device(libusb_device_handle *dev); |
| int LIBUSB_CALL libusb_kernel_driver_active(libusb_device_handle *dev, |
| int interface_number); |
| int LIBUSB_CALL libusb_detach_kernel_driver(libusb_device_handle *dev, |
| int interface_number); |
| int LIBUSB_CALL libusb_attach_kernel_driver(libusb_device_handle *dev, |
| int interface_number); |
| /* async I/O */ |
| /** \ingroup asyncio |
| * Get the data section of a control transfer. This convenience function is here |
| * to remind you that the data does not start until 8 bytes into the actual |
| * buffer, as the setup packet comes first. |
| * |
| * Calling this function only makes sense from a transfer callback function, |
| * or situations where you have already allocated a suitably sized buffer at |
| * transfer->buffer. |
| * |
| * \param transfer a transfer |
| * \returns pointer to the first byte of the data section |
| */ |
| static inline unsigned char *libusb_control_transfer_get_data( |
| struct libusb_transfer *transfer) |
| { |
| return transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE; |
| } |
| /** \ingroup asyncio |
| * Get the control setup packet of a control transfer. This convenience |
| * function is here to remind you that the control setup occupies the first |
| * 8 bytes of the transfer data buffer. |
| * |
| * Calling this function only makes sense from a transfer callback function, |
| * or situations where you have already allocated a suitably sized buffer at |
| * transfer->buffer. |
| * |
| * \param transfer a transfer |
| * \returns a casted pointer to the start of the transfer data buffer |
| */ |
| static inline struct libusb_control_setup *libusb_control_transfer_get_setup( |
| struct libusb_transfer *transfer) |
| { |
| return (struct libusb_control_setup *) transfer->buffer; |
| } |
| /** \ingroup asyncio |
| * Helper function to populate the setup packet (first 8 bytes of the data |
| * buffer) for a control transfer. The wIndex, wValue and wLength values should |
| * be given in host-endian byte order. |
| * |
| * \param buffer buffer to output the setup packet into |
| * \param bmRequestType see the |
| * \ref libusb_control_setup::bmRequestType "bmRequestType" field of |
| * \ref libusb_control_setup |
| * \param bRequest see the |
| * \ref libusb_control_setup::bRequest "bRequest" field of |
| * \ref libusb_control_setup |
| * \param wValue see the |
| * \ref libusb_control_setup::wValue "wValue" field of |
| * \ref libusb_control_setup |
| * \param wIndex see the |
| * \ref libusb_control_setup::wIndex "wIndex" field of |
| * \ref libusb_control_setup |
| * \param wLength see the |
| * \ref libusb_control_setup::wLength "wLength" field of |
| * \ref libusb_control_setup |
| */ |
| static inline void libusb_fill_control_setup(unsigned char *buffer, |
| uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, |
| uint16_t wLength) |
| { |
| struct libusb_control_setup *setup = (struct libusb_control_setup *) buffer; |
| setup->bmRequestType = bmRequestType; |
| setup->bRequest = bRequest; |
| setup->wValue = libusb_cpu_to_le16(wValue); |
| setup->wIndex = libusb_cpu_to_le16(wIndex); |
| setup->wLength = libusb_cpu_to_le16(wLength); |
| } |
| struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer(int iso_packets); |
| int LIBUSB_CALL libusb_submit_transfer(struct libusb_transfer *transfer); |
| int LIBUSB_CALL libusb_cancel_transfer(struct libusb_transfer *transfer); |
| void LIBUSB_CALL libusb_free_transfer(struct libusb_transfer *transfer); |
| /** \ingroup asyncio |
| * Helper function to populate the required \ref libusb_transfer fields |
| * for a control transfer. |
| * |
| * If you pass a transfer buffer to this function, the first 8 bytes will |
| * be interpreted as a control setup packet, and the wLength field will be |
| * used to automatically populate the \ref libusb_transfer::length "length" |
| * field of the transfer. Therefore the recommended approach is: |
| * -# Allocate a suitably sized data buffer (including space for control setup) |
| * -# Call libusb_fill_control_setup() |
| * -# If this is a host-to-device transfer with a data stage, put the data |
| * in place after the setup packet |
| * -# Call this function |
| * -# Call libusb_submit_transfer() |
| * |
| * It is also legal to pass a NULL buffer to this function, in which case this |
| * function will not attempt to populate the length field. Remember that you |
| * must then populate the buffer and length fields later. |
| * |
| * \param transfer the transfer to populate |
| * \param dev_handle handle of the device that will handle the transfer |
| * \param buffer data buffer. If provided, this function will interpret the |
| * first 8 bytes as a setup packet and infer the transfer length from that. |
| * \param callback callback function to be invoked on transfer completion |
| * \param user_data user data to pass to callback function |
| * \param timeout timeout for the transfer in milliseconds |
| */ |
| static inline void libusb_fill_control_transfer( |
| struct libusb_transfer *transfer, libusb_device_handle *dev_handle, |
| unsigned char *buffer, libusb_transfer_cb_fn callback, void *user_data, |
| unsigned int timeout) |
| { |
| struct libusb_control_setup *setup = (struct libusb_control_setup *) buffer; |
| transfer->dev_handle = dev_handle; |
| transfer->endpoint = 0; |
| transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL; |
| transfer->timeout = timeout; |
| transfer->buffer = buffer; |
| if (setup) |
| transfer->length = LIBUSB_CONTROL_SETUP_SIZE |
| + libusb_le16_to_cpu(setup->wLength); |
| transfer->user_data = user_data; |
| transfer->callback = callback; |
| } |
| /** \ingroup asyncio |
| * Helper function to populate the required \ref libusb_transfer fields |
| * for a bulk transfer. |
| * |
| * \param transfer the transfer to populate |
| * \param dev_handle handle of the device that will handle the transfer |
| * \param endpoint address of the endpoint where this transfer will be sent |
| * \param buffer data buffer |
| * \param length length of data buffer |
| * \param callback callback function to be invoked on transfer completion |
| * \param user_data user data to pass to callback function |
| * \param timeout timeout for the transfer in milliseconds |
| */ |
| static inline void libusb_fill_bulk_transfer(struct libusb_transfer *transfer, |
| libusb_device_handle *dev_handle, unsigned char endpoint, |
| unsigned char *buffer, int length, libusb_transfer_cb_fn callback, |
| void *user_data, unsigned int timeout) |
| { |
| transfer->dev_handle = dev_handle; |
| transfer->endpoint = endpoint; |
| transfer->type = LIBUSB_TRANSFER_TYPE_BULK; |
| transfer->timeout = timeout; |
| transfer->buffer = buffer; |
| transfer->length = length; |
| transfer->user_data = user_data; |
| transfer->callback = callback; |
| } |
| /** \ingroup asyncio |
| * Helper function to populate the required \ref libusb_transfer fields |
| * for an interrupt transfer. |
| * |
| * \param transfer the transfer to populate |
| * \param dev_handle handle of the device that will handle the transfer |
| * \param endpoint address of the endpoint where this transfer will be sent |
| * \param buffer data buffer |
| * \param length length of data buffer |
| * \param callback callback function to be invoked on transfer completion |
| * \param user_data user data to pass to callback function |
| * \param timeout timeout for the transfer in milliseconds |
| */ |
| static inline void libusb_fill_interrupt_transfer( |
| struct libusb_transfer *transfer, libusb_device_handle *dev_handle, |
| unsigned char endpoint, unsigned char *buffer, int length, |
| libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) |
| { |
| transfer->dev_handle = dev_handle; |
| transfer->endpoint = endpoint; |
| transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT; |
| transfer->timeout = timeout; |
| transfer->buffer = buffer; |
| transfer->length = length; |
| transfer->user_data = user_data; |
| transfer->callback = callback; |
| } |
| /** \ingroup asyncio |
| * Helper function to populate the required \ref libusb_transfer fields |
| * for an isochronous transfer. |
| * |
| * \param transfer the transfer to populate |
| * \param dev_handle handle of the device that will handle the transfer |
| * \param endpoint address of the endpoint where this transfer will be sent |
| * \param buffer data buffer |
| * \param length length of data buffer |
| * \param num_iso_packets the number of isochronous packets |
| * \param callback callback function to be invoked on transfer completion |
| * \param user_data user data to pass to callback function |
| * \param timeout timeout for the transfer in milliseconds |
| */ |
| static inline void libusb_fill_iso_transfer(struct libusb_transfer *transfer, |
| libusb_device_handle *dev_handle, unsigned char endpoint, |
| unsigned char *buffer, int length, int num_iso_packets, |
| libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) |
| { |
| transfer->dev_handle = dev_handle; |
| transfer->endpoint = endpoint; |
| transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS; |
| transfer->timeout = timeout; |
| transfer->buffer = buffer; |
| transfer->length = length; |
| transfer->num_iso_packets = num_iso_packets; |
| transfer->user_data = user_data; |
| transfer->callback = callback; |
| } |
| /** \ingroup asyncio |
| * Convenience function to set the length of all packets in an isochronous |
| * transfer, based on the num_iso_packets field in the transfer structure. |
| * |
| * \param transfer a transfer |
| * \param length the length to set in each isochronous packet descriptor |
| * \see libusb_get_max_packet_size() |
| */ |
| static inline void libusb_set_iso_packet_lengths( |
| struct libusb_transfer *transfer, unsigned int length) |
| { |
| int i; |
| for (i = 0; i < transfer->num_iso_packets; i++) |
| transfer->iso_packet_desc[i].length = length; |
| } |
| /** \ingroup asyncio |
| * Convenience function to locate the position of an isochronous packet |
| * within the buffer of an isochronous transfer. |
| * |
| * This is a thorough function which loops through all preceding packets, |
| * accumulating their lengths to find the position of the specified packet. |
| * Typically you will assign equal lengths to each packet in the transfer, |
| * and hence the above method is sub-optimal. You may wish to use |
| * libusb_get_iso_packet_buffer_simple() instead. |
| * |
| * \param transfer a transfer |
| * \param packet the packet to return the address of |
| * \returns the base address of the packet buffer inside the transfer buffer, |
| * or NULL if the packet does not exist. |
| * \see libusb_get_iso_packet_buffer_simple() |
| */ |
| static inline unsigned char *libusb_get_iso_packet_buffer( |
| struct libusb_transfer *transfer, unsigned int packet) |
| { |
| int i; |
| size_t offset = 0; |
| int _packet; |
| /* oops..slight bug in the API. packet is an unsigned int, but we use |
| * signed integers almost everywhere else. range-check and convert to |
| * signed to avoid compiler warnings. FIXME for libusb-2. */ |
| if (packet > INT_MAX) |
| return NULL; |
| _packet = packet; |
| if (_packet >= transfer->num_iso_packets) |
| return NULL; |
| for (i = 0; i < _packet; i++) |
| offset += transfer->iso_packet_desc[i].length; |
| return transfer->buffer + offset; |
| } |
| /** \ingroup asyncio |
| * Convenience function to locate the position of an isochronous packet |
| * within the buffer of an isochronous transfer, for transfers where each |
| * packet is of identical size. |
| * |
| * This function relies on the assumption that every packet within the transfer |
| * is of identical size to the first packet. Calculating the location of |
| * the packet buffer is then just a simple calculation: |
| * <tt>buffer + (packet_size * packet)</tt> |
| * |
| * Do not use this function on transfers other than those that have identical |
| * packet lengths for each packet. |
| * |
| * \param transfer a transfer |
| * \param packet the packet to return the address of |
| * \returns the base address of the packet buffer inside the transfer buffer, |
| * or NULL if the packet does not exist. |
| * \see libusb_get_iso_packet_buffer() |
| */ |
| static inline unsigned char *libusb_get_iso_packet_buffer_simple( |
| struct libusb_transfer *transfer, unsigned int packet) |
| { |
| int _packet; |
| /* oops..slight bug in the API. packet is an unsigned int, but we use |
| * signed integers almost everywhere else. range-check and convert to |
| * signed to avoid compiler warnings. FIXME for libusb-2. */ |
| if (packet > INT_MAX) |
| return NULL; |
| _packet = packet; |
| if (_packet >= transfer->num_iso_packets) |
| return NULL; |
| return transfer->buffer + (transfer->iso_packet_desc[0].length * _packet); |
| } |
| /* sync I/O */ |
| int LIBUSB_CALL libusb_control_transfer(libusb_device_handle *dev_handle, |
| uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, |
| unsigned char *data, uint16_t wLength, unsigned int timeout); |
| int LIBUSB_CALL libusb_bulk_transfer(libusb_device_handle *dev_handle, |
| unsigned char endpoint, unsigned char *data, int length, |
| int *actual_length, unsigned int timeout); |
| int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle *dev_handle, |
| unsigned char endpoint, unsigned char *data, int length, |
| int *actual_length, unsigned int timeout); |
| /** \ingroup desc |
| * Retrieve a descriptor from the default control pipe. |
| * This is a convenience function which formulates the appropriate control |
| * message to retrieve the descriptor. |
| * |
| * \param dev a device handle |
| * \param desc_type the descriptor type, see \ref libusb_descriptor_type |
| * \param desc_index the index of the descriptor to retrieve |
| * \param data output buffer for descriptor |
| * \param length size of data buffer |
| * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure |
| */ |
| static inline int libusb_get_descriptor(libusb_device_handle *dev, |
| uint8_t desc_type, uint8_t desc_index, unsigned char *data, int length) |
| { |
| return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, |
| LIBUSB_REQUEST_GET_DESCRIPTOR, (desc_type << 8) | desc_index, 0, data, |
| (uint16_t) length, 1000); |
| } |
| /** \ingroup desc |
| * Retrieve a descriptor from a device. |
| * This is a convenience function which formulates the appropriate control |
| * message to retrieve the descriptor. The string returned is Unicode, as |
| * detailed in the USB specifications. |
| * |
| * \param dev a device handle |
| * \param desc_index the index of the descriptor to retrieve |
| * \param langid the language ID for the string descriptor |
| * \param data output buffer for descriptor |
| * \param length size of data buffer |
| * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure |
| * \see libusb_get_string_descriptor_ascii() |
| */ |
| static inline int libusb_get_string_descriptor(libusb_device_handle *dev, |
| uint8_t desc_index, uint16_t langid, unsigned char *data, int length) |
| { |
| return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, |
| LIBUSB_REQUEST_GET_DESCRIPTOR, (uint16_t)((LIBUSB_DT_STRING << 8) | desc_index), |
| langid, data, (uint16_t) length, 1000); |
| } |
| int LIBUSB_CALL libusb_get_string_descriptor_ascii(libusb_device_handle *dev, |
| uint8_t desc_index, unsigned char *data, int length); |
| /* polling and timeouts */ |
| int LIBUSB_CALL libusb_try_lock_events(libusb_context *ctx); |
| void LIBUSB_CALL libusb_lock_events(libusb_context *ctx); |
| void LIBUSB_CALL libusb_unlock_events(libusb_context *ctx); |
| int LIBUSB_CALL libusb_event_handling_ok(libusb_context *ctx); |
| int LIBUSB_CALL libusb_event_handler_active(libusb_context *ctx); |
| void LIBUSB_CALL libusb_lock_event_waiters(libusb_context *ctx); |
| void LIBUSB_CALL libusb_unlock_event_waiters(libusb_context *ctx); |
| int LIBUSB_CALL libusb_wait_for_event(libusb_context *ctx, struct timeval *tv); |
| int LIBUSB_CALL libusb_handle_events_timeout(libusb_context *ctx, |
| struct timeval *tv); |
| int LIBUSB_CALL libusb_handle_events_timeout_completed(libusb_context *ctx, |
| struct timeval *tv, int *completed); |
| int LIBUSB_CALL libusb_handle_events(libusb_context *ctx); |
| int LIBUSB_CALL libusb_handle_events_completed(libusb_context *ctx, int *completed); |
| int LIBUSB_CALL libusb_handle_events_locked(libusb_context *ctx, |
| struct timeval *tv); |
| int LIBUSB_CALL libusb_pollfds_handle_timeouts(libusb_context *ctx); |
| int LIBUSB_CALL libusb_get_next_timeout(libusb_context *ctx, |
| struct timeval *tv); |
| /** \ingroup poll |
| * File descriptor for polling |
| */ |
| struct libusb_pollfd { |
| /** Numeric file descriptor */ |
| int fd; |
| /** Event flags to poll for from <poll.h>. POLLIN indicates that you |
| * should monitor this file descriptor for becoming ready to read from, |
| * and POLLOUT indicates that you should monitor this file descriptor for |
| * nonblocking write readiness. */ |
| short events; |
| }; |
| /** \ingroup poll |
| * Callback function, invoked when a new file descriptor should be added |
| * to the set of file descriptors monitored for events. |
| * \param fd the new file descriptor |
| * \param events events to monitor for, see \ref libusb_pollfd for a |
| * description |
| * \param user_data User data pointer specified in |
| * libusb_set_pollfd_notifiers() call |
| * \see libusb_set_pollfd_notifiers() |
| */ |
| typedef void (LIBUSB_CALL *libusb_pollfd_added_cb)(int fd, short events, |
| void *user_data); |
| /** \ingroup poll |
| * Callback function, invoked when a file descriptor should be removed from |
| * the set of file descriptors being monitored for events. After returning |
| * from this callback, do not use that file descriptor again. |
| * \param fd the file descriptor to stop monitoring |
| * \param user_data User data pointer specified in |
| * libusb_set_pollfd_notifiers() call |
| * \see libusb_set_pollfd_notifiers() |
| */ |
| typedef void (LIBUSB_CALL *libusb_pollfd_removed_cb)(int fd, void *user_data); |
| const struct libusb_pollfd ** LIBUSB_CALL libusb_get_pollfds( |
| libusb_context *ctx); |
| void LIBUSB_CALL libusb_set_pollfd_notifiers(libusb_context *ctx, |
| libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb, |
| void *user_data); |
| #ifdef __cplusplus |
| } |
| #endif |
| #endif |
| /cvi/instr/drsctrl/libusb-1.0.lib |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |
| /cvi/instr/drsctrl/musbstd.c |
|---|
| 0,0 → 1,700 |
| /********************************************************************\ |
| Name: musbstd.c |
| Created by: Konstantin Olchanski, Stefan Ritt |
| Contents: Midas USB access |
| $Id$ |
| \********************************************************************/ |
| #include <stdio.h> |
| #include <assert.h> |
| #include "musbstd.h" |
| #ifdef _MSC_VER // Windows includes |
| #include <windows.h> |
| #include <conio.h> |
| #include <winioctl.h> |
| #include <setupapi.h> |
| #include <initguid.h> /* Required for GUID definition */ |
| // link with SetupAPI.Lib. |
| #pragma comment (lib, "setupapi.lib") |
| // disable "deprecated" warning |
| #pragma warning( disable: 4996) |
| // {CBEB3FB1-AE9F-471c-9016-9B6AC6DCD323} |
| DEFINE_GUID(GUID_CLASS_MSCB_BULK, 0xcbeb3fb1, 0xae9f, 0x471c, 0x90, 0x16, 0x9b, 0x6a, 0xc6, 0xdc, 0xd3, 0x23); |
| #elif defined(OS_DARWIN) |
| #include <unistd.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <ctype.h> |
| #include <sys/types.h> |
| #include <sys/ioctl.h> |
| #include <sys/time.h> |
| #include <fcntl.h> |
| #include <assert.h> |
| #include <mach/mach.h> |
| #include <IOKit/IOKitLib.h> |
| #include <IOKit/IOCFPlugIn.h> |
| #include <IOKit/usb/IOUSBLib.h> |
| #elif defined(OS_LINUX) // Linux includes |
| #include <unistd.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #endif |
| #ifdef HAVE_LIBUSB |
| #include <errno.h> |
| #include "usb.h" |
| #endif |
| #ifdef HAVE_LIBUSB10 |
| #include <errno.h> |
| #include <libusb-1.0/libusb.h> |
| #endif |
| #if !defined(HAVE_LIBUSB) && !defined(HAVE_LIBUSB10) |
| #ifdef OS_DARWIN |
| IOReturn darwin_configure_device(MUSB_INTERFACE* musb) |
| { |
| IOReturn status; |
| io_iterator_t iter; |
| io_service_t service; |
| IOCFPlugInInterface **plugin; |
| SInt32 score; |
| IOUSBInterfaceInterface **uinterface; |
| UInt8 numend; |
| IOUSBDeviceInterface **device = (IOUSBDeviceInterface **)musb->device; |
| status = (*device)->SetConfiguration(device, musb->usb_configuration); |
| assert(status == kIOReturnSuccess); |
| IOUSBFindInterfaceRequest request; |
| request.bInterfaceClass = kIOUSBFindInterfaceDontCare; |
| request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; |
| request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; |
| request.bAlternateSetting = kIOUSBFindInterfaceDontCare; |
| status = (*device)->CreateInterfaceIterator(device, &request, &iter); |
| assert(status == kIOReturnSuccess); |
| while ((service = IOIteratorNext(iter))) { |
| int i; |
| status = |
| IOCreatePlugInInterfaceForService(service, kIOUSBInterfaceUserClientTypeID, |
| kIOCFPlugInInterfaceID, &plugin, &score); |
| assert(status == kIOReturnSuccess); |
| status = |
| (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), |
| (void *) &uinterface); |
| assert(status == kIOReturnSuccess); |
| status = (*uinterface)->USBInterfaceOpen(uinterface); |
| fprintf(stderr, "musb_open: USBInterfaceOpen status 0x%x\n", status); |
| assert(status == kIOReturnSuccess); |
| status = (*uinterface)->GetNumEndpoints(uinterface, &numend); |
| assert(status == kIOReturnSuccess); |
| fprintf(stderr, "musb_open: endpoints: %d\n", numend); |
| for (i=1; i<=numend; i++) { |
| status = (*uinterface)->GetPipeStatus(uinterface, i); |
| fprintf(stderr, "musb_open: pipe %d status: 0x%x\n", i, status); |
| #if 0 |
| status = (*uinterface)->ClearPipeStall(uinterface, i); |
| fprintf(stderr, "musb_open: pipe %d ClearPipeStall() status: 0x%x\n", i, status); |
| status = (*uinterface)->ResetPipe(uinterface, i); |
| fprintf(stderr, "musb_open: pipe %d ResetPipe() status: 0x%x\n", i, status); |
| status = (*uinterface)->AbortPipe(uinterface, i); |
| fprintf(stderr, "musb_open: pipe %d AbortPipe() status: 0x%x\n", i, status); |
| #endif |
| } |
| musb->interface = uinterface; |
| return kIOReturnSuccess; |
| } |
| assert(!"Should never be reached!"); |
| return -1; |
| } |
| #endif |
| #endif |
| int musb_open(MUSB_INTERFACE **musb_interface, int vendor, int product, int instance, int configuration, int usbinterface) |
| { |
| #if defined(HAVE_LIBUSB) |
| struct usb_bus *bus; |
| struct usb_device *dev; |
| int count = 0; |
| usb_init(); |
| usb_find_busses(); |
| usb_find_devices(); |
| usb_set_debug(3); |
| for (bus = usb_get_busses(); bus; bus = bus->next) |
| for (dev = bus->devices; dev; dev = dev->next) |
| if (dev->descriptor.idVendor == vendor && dev->descriptor.idProduct == product) { |
| if (count == instance) { |
| int status; |
| usb_dev_handle *udev; |
| udev = usb_open(dev); |
| if (!udev) { |
| fprintf(stderr, "musb_open: usb_open() error\n"); |
| return MUSB_ACCESS_ERROR; |
| } |
| status = usb_set_configuration(udev, configuration); |
| if (status < 0) { |
| fprintf(stderr, "musb_open: usb_set_configuration() error %d (%s)\n", status, |
| strerror(-status)); |
| fprintf(stderr, |
| "musb_open: Found USB device 0x%04x:0x%04x instance %d, but cannot initialize it: please check permissions on \"/proc/bus/usb/%s/%s\" and \"/dev/bus/usb/%s/%s\"\n", |
| vendor, product, instance, bus->dirname, dev->filename, bus->dirname, dev->filename); |
| return MUSB_ACCESS_ERROR; |
| } |
| /* see if we have write access */ |
| status = usb_claim_interface(udev, usbinterface); |
| if (status < 0) { |
| fprintf(stderr, "musb_open: usb_claim_interface() error %d (%s)\n", status, |
| strerror(-status)); |
| #ifdef _MSC_VER |
| fprintf(stderr, |
| "musb_open: Found USB device 0x%04x:0x%04x instance %d, but cannot initialize it:\nDevice is probably used by another program\n", |
| vendor, product, instance); |
| #else |
| fprintf(stderr, |
| "musb_open: Found USB device 0x%04x:0x%04x instance %d, but cannot initialize it: please check permissions on \"/proc/bus/usb/%s/%s\"\n", |
| vendor, product, instance, bus->dirname, dev->filename); |
| #endif |
| return MUSB_ACCESS_ERROR; |
| } |
| *musb_interface = (MUSB_INTERFACE*)calloc(1, sizeof(MUSB_INTERFACE)); |
| (*musb_interface)->dev = udev; |
| (*musb_interface)->usb_configuration = configuration; |
| (*musb_interface)->usb_interface = usbinterface; |
| return MUSB_SUCCESS; |
| } |
| count++; |
| } |
| return MUSB_NOT_FOUND; |
| #elif defined(HAVE_LIBUSB10) |
| static int first_call = 1; |
| libusb_device **dev_list; |
| libusb_device_handle *dev; |
| struct libusb_device_descriptor desc; |
| int status, i, n; |
| int count = 0; |
| if (first_call) { |
| first_call = 0; |
| libusb_init(NULL); |
| // libusb_set_debug(NULL, 3); |
| } |
| n = libusb_get_device_list(NULL, &dev_list); |
| for (i=0 ; i<n ; i++) { |
| status = libusb_get_device_descriptor(dev_list[i], &desc); |
| if (desc.idVendor == vendor && desc.idProduct == product) { |
| if (count == instance) { |
| status = libusb_open(dev_list[i], &dev); |
| if (status < 0) { |
| fprintf(stderr, "musb_open: libusb_open() error %d\n", status); |
| return MUSB_ACCESS_ERROR; |
| } |
| status = libusb_set_configuration(dev, configuration); |
| if (status < 0) { |
| fprintf(stderr, "musb_open: usb_set_configuration() error %d\n", status); |
| fprintf(stderr, |
| "musb_open: Found USB device 0x%04x:0x%04x instance %d, but cannot initialize it: please check permissions on \"/proc/bus/usb/%d/%d\" and \"/dev/bus/usb/%d/%d\"\n", |
| vendor, product, instance, libusb_get_bus_number(dev_list[i]), libusb_get_device_address(dev_list[i]), libusb_get_bus_number(dev_list[i]), libusb_get_device_address(dev_list[i])); |
| return MUSB_ACCESS_ERROR; |
| } |
| /* see if we have write access */ |
| status = libusb_claim_interface(dev, usbinterface); |
| if (status < 0) { |
| fprintf(stderr, "musb_open: libusb_claim_interface() error %d\n", status); |
| #ifdef _MSC_VER |
| fprintf(stderr, |
| "musb_open: Found USB device 0x%04x:0x%04x instance %d, but cannot initialize it:\nDevice is probably used by another program\n", |
| vendor, product, instance); |
| #else |
| fprintf(stderr, |
| "musb_open: Found USB device 0x%04x:0x%04x instance %d, but cannot initialize it: please check permissions on \"/proc/bus/usb/%d/%d\"\n", |
| vendor, product, instance, libusb_get_bus_number(dev_list[i]), libusb_get_device_address(dev_list[i])); |
| #endif |
| return MUSB_ACCESS_ERROR; |
| } |
| *musb_interface = (MUSB_INTERFACE*)calloc(1, sizeof(MUSB_INTERFACE)); |
| (*musb_interface)->dev = dev; |
| (*musb_interface)->usb_configuration = configuration; |
| (*musb_interface)->usb_interface = usbinterface; |
| return MUSB_SUCCESS; |
| } |
| count++; |
| } |
| } |
| libusb_free_device_list(dev_list, 1); |
| return MUSB_NOT_FOUND; |
| #elif defined(OS_DARWIN) |
| kern_return_t status; |
| io_iterator_t iter; |
| io_service_t service; |
| IOCFPlugInInterface **plugin; |
| SInt32 score; |
| IOUSBDeviceInterface **device; |
| UInt16 xvendor, xproduct; |
| int count = 0; |
| *musb_interface = calloc(1, sizeof(MUSB_INTERFACE)); |
| status = IORegistryCreateIterator(kIOMasterPortDefault, kIOUSBPlane, kIORegistryIterateRecursively, &iter); |
| assert(status == kIOReturnSuccess); |
| while ((service = IOIteratorNext(iter))) { |
| status = |
| IOCreatePlugInInterfaceForService(service, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, |
| &plugin, &score); |
| assert(status == kIOReturnSuccess); |
| status = IOObjectRelease(service); |
| assert(status == kIOReturnSuccess); |
| status = |
| (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (void *) &device); |
| assert(status == kIOReturnSuccess); |
| status = (*plugin)->Release(plugin); |
| status = (*device)->GetDeviceVendor(device, &xvendor); |
| assert(status == kIOReturnSuccess); |
| status = (*device)->GetDeviceProduct(device, &xproduct); |
| assert(status == kIOReturnSuccess); |
| //fprintf(stderr, "musb_open: Found USB device: vendor 0x%04x, product 0x%04x\n", xvendor, xproduct); |
| if (xvendor == vendor && xproduct == product) { |
| if (count == instance) { |
| fprintf(stderr, "musb_open: Found USB device: vendor 0x%04x, product 0x%04x, instance %d\n", xvendor, xproduct, instance); |
| status = (*device)->USBDeviceOpen(device); |
| fprintf(stderr, "musb_open: USBDeviceOpen status 0x%x\n", status); |
| assert(status == kIOReturnSuccess); |
| (*musb_interface)->usb_configuration = configuration; |
| (*musb_interface)->usb_interface = usbinterface; |
| (*musb_interface)->device = (void*)device; |
| (*musb_interface)->interface = NULL; |
| status = darwin_configure_device(*musb_interface); |
| if (status == kIOReturnSuccess) |
| return MUSB_SUCCESS; |
| fprintf(stderr, "musb_open: USB device exists, but configuration fails!"); |
| return MUSB_NOT_FOUND; |
| } |
| count++; |
| } |
| (*device)->Release(device); |
| } |
| return MUSB_NOT_FOUND; |
| #elif defined(_MSC_VER) |
| GUID guid; |
| HDEVINFO hDevInfoList; |
| SP_DEVICE_INTERFACE_DATA deviceInfoData; |
| PSP_DEVICE_INTERFACE_DETAIL_DATA functionClassDeviceData; |
| ULONG predictedLength, requiredLength; |
| int status; |
| char device_name[256], str[256]; |
| *musb_interface = (MUSB_INTERFACE *)calloc(1, sizeof(MUSB_INTERFACE)); |
| guid = GUID_CLASS_MSCB_BULK; |
| // Retrieve device list for GUID that has been specified. |
| hDevInfoList = SetupDiGetClassDevs(&guid, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); |
| status = FALSE; |
| if (hDevInfoList != NULL) { |
| // Clear data structure |
| memset(&deviceInfoData, 0, sizeof(deviceInfoData)); |
| deviceInfoData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); |
| // retrieves a context structure for a device interface of a device information set. |
| if (SetupDiEnumDeviceInterfaces(hDevInfoList, 0, &guid, instance, &deviceInfoData)) { |
| // Must get the detailed information in two steps |
| // First get the length of the detailed information and allocate the buffer |
| // retrieves detailed information about a specified device interface. |
| functionClassDeviceData = NULL; |
| predictedLength = requiredLength = 0; |
| SetupDiGetDeviceInterfaceDetail(hDevInfoList, &deviceInfoData, NULL, // Not yet allocated |
| 0, // Set output buffer length to zero |
| &requiredLength, // Find out memory requirement |
| NULL); |
| predictedLength = requiredLength; |
| functionClassDeviceData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(predictedLength); |
| functionClassDeviceData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); |
| // Second, get the detailed information |
| if (SetupDiGetDeviceInterfaceDetail(hDevInfoList, |
| &deviceInfoData, functionClassDeviceData, |
| predictedLength, &requiredLength, NULL)) { |
| // Save the device name for subsequent pipe open calls |
| strcpy(device_name, functionClassDeviceData->DevicePath); |
| free(functionClassDeviceData); |
| // Signal device found |
| status = TRUE; |
| } else |
| free(functionClassDeviceData); |
| } |
| } |
| // SetupDiDestroyDeviceInfoList() destroys a device information set |
| // and frees all associated memory. |
| SetupDiDestroyDeviceInfoList(hDevInfoList); |
| if (status) { |
| // Get the read handle |
| sprintf(str, "%s\\PIPE00", device_name); |
| (*musb_interface)->rhandle = CreateFile(str, |
| GENERIC_WRITE | GENERIC_READ, |
| FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, |
| OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); |
| if ((*musb_interface)->rhandle == INVALID_HANDLE_VALUE) |
| return MUSB_ACCESS_ERROR; |
| // Get the write handle |
| sprintf(str, "%s\\PIPE01", device_name); |
| (*musb_interface)->whandle = CreateFile(str, |
| GENERIC_WRITE | GENERIC_READ, |
| FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); |
| if ((*musb_interface)->whandle == INVALID_HANDLE_VALUE) |
| return MUSB_ACCESS_ERROR; |
| return MUSB_SUCCESS; |
| } |
| return MUSB_NOT_FOUND; |
| #endif |
| } |
| int musb_set_altinterface(MUSB_INTERFACE *musb_interface, int index) |
| { |
| #if defined (HAVE_LIBUSB) |
| int status; |
| status = usb_set_altinterface(musb_interface->dev, index); |
| if (status < 0) |
| fprintf(stderr, "musb_set_altinterface: usb_set_altinterface() error %d\n", status); |
| return status; |
| #else |
| return -1; |
| #endif |
| } |
| int musb_close(MUSB_INTERFACE *musb_interface) |
| { |
| #if defined(HAVE_LIBUSB) |
| int status; |
| status = usb_release_interface(musb_interface->dev, musb_interface->usb_interface); |
| if (status < 0) |
| fprintf(stderr, "musb_close: usb_release_interface() error %d\n", status); |
| #ifdef OS_LINUX // linux wants a reset, otherwise the device cannot be accessed next time |
| musb_reset(musb_interface); |
| #endif |
| status = usb_close(musb_interface->dev); |
| if (status < 0) |
| fprintf(stderr, "musb_close: usb_close() error %d\n", status); |
| #elif defined(HAVE_LIBUSB10) |
| int status; |
| status = libusb_release_interface(musb_interface->dev, musb_interface->usb_interface); |
| if (status < 0) |
| fprintf(stderr, "musb_close: libusb_release_interface() error %d\n", status); |
| #ifdef OS_LINUX // linux wants a reset, otherwise the device cannot be accessed next time |
| musb_reset(musb_interface); |
| #endif |
| libusb_close(musb_interface->dev); |
| #elif defined(OS_DARWIN) |
| IOReturn status; |
| IOUSBInterfaceInterface **interface = (IOUSBInterfaceInterface **)musb_interface->interface; |
| status = (*interface)->USBInterfaceClose(interface); |
| if (status != kIOReturnSuccess) |
| fprintf(stderr, "musb_close: USBInterfaceClose() status %d 0x%x\n", status, status); |
| status = (*interface)->Release(interface); |
| if (status != kIOReturnSuccess) |
| fprintf(stderr, "musb_close: USB Interface Release() status %d 0x%x\n", status, status); |
| IOUSBDeviceInterface **device = (IOUSBDeviceInterface**)musb_interface->device; |
| status = (*device)->USBDeviceClose(device); |
| if (status != kIOReturnSuccess) |
| fprintf(stderr, "musb_close: USBDeviceClose() status %d 0x%x\n", status, status); |
| status = (*device)->Release(device); |
| if (status != kIOReturnSuccess) |
| fprintf(stderr, "musb_close: USB Device Release() status %d 0x%x\n", status, status); |
| #elif defined(_MSC_VER) |
| CloseHandle(musb_interface->rhandle); |
| CloseHandle(musb_interface->whandle); |
| #else |
| assert(!"musb_close() is not implemented"); |
| #endif |
| /* free memory allocated in musb_open() */ |
| free(musb_interface); |
| return 0; |
| } |
| int musb_write(MUSB_INTERFACE *musb_interface, int endpoint, const void *buf, int count, int timeout) |
| { |
| int n_written; |
| #if defined(HAVE_LIBUSB) |
| n_written = usb_bulk_write(musb_interface->dev, endpoint, (char*)buf, count, timeout); |
| if (n_written != count) { |
| fprintf(stderr, "musb_write: requested %d, wrote %d, errno %d (%s)\n", count, n_written, errno, strerror(errno)); |
| } |
| #elif defined(HAVE_LIBUSB10) |
| int status = libusb_bulk_transfer(musb_interface->dev, endpoint, (unsigned char*)buf, count, &n_written, timeout); |
| if (n_written != count) { |
| fprintf(stderr, "musb_write: requested %d, wrote %d, errno %d (%s)\n", count, n_written, status, strerror(status)); |
| } |
| #elif defined(OS_DARWIN) |
| IOReturn status; |
| IOUSBInterfaceInterface182 **interface = (IOUSBInterfaceInterface182 **)musb_interface->interface; |
| status = (*interface)->WritePipeTO(interface, endpoint, buf, count, 0, timeout); |
| if (status != 0) { |
| fprintf(stderr, "musb_write: WritePipe() status %d 0x%x\n", status, status); |
| return -1; |
| } |
| n_written = count; |
| #elif defined(_MSC_VER) |
| WriteFile(musb_interface->whandle, buf, count, &n_written, NULL); |
| #endif |
| //fprintf(stderr, "musb_write(ep %d, %d bytes) (%s) returns %d\n", endpoint, count, buf, n_written); |
| return n_written; |
| } |
| int musb_read(MUSB_INTERFACE *musb_interface, int endpoint, void *buf, int count, int timeout) |
| { |
| int n_read = 0; |
| #if defined(HAVE_LIBUSB) |
| n_read = usb_bulk_read(musb_interface->dev, endpoint | 0x80, (char*)buf, count, timeout); |
| /* errors should be handled in upper layer .... |
| if (n_read <= 0) { |
| fprintf(stderr, "musb_read: requested %d, read %d, errno %d (%s)\n", count, n_read, errno, strerror(errno)); |
| } |
| */ |
| #elif defined(HAVE_LIBUSB10) |
| libusb_bulk_transfer(musb_interface->dev, endpoint | 0x80, (unsigned char*)buf, count, &n_read, timeout); |
| /* errors should be handled in upper layer .... |
| if (n_read <= 0) { |
| fprintf(stderr, "musb_read: requested %d, read %d, errno %d (%s)\n", count, n_read, status, strerror(status)); |
| } |
| */ |
| #elif defined(OS_DARWIN) |
| UInt32 xcount = count; |
| IOReturn status; |
| IOUSBInterfaceInterface182 **interface = (IOUSBInterfaceInterface182 **)musb_interface->interface; |
| status = (*interface)->ReadPipeTO(interface, endpoint, buf, &xcount, 0, timeout); |
| if (status != kIOReturnSuccess) { |
| fprintf(stderr, "musb_read: requested %d, read %d, ReadPipe() status %d 0x%x (%s)\n", count, n_read, status, status, strerror(status)); |
| return -1; |
| } |
| n_read = xcount; |
| #elif defined(_MSC_VER) |
| OVERLAPPED overlapped; |
| int status; |
| memset(&overlapped, 0, sizeof(overlapped)); |
| overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); |
| n_read = 0; |
| status = ReadFile(musb_interface->rhandle, buf, count, &n_read, &overlapped); |
| if (!status) { |
| status = GetLastError(); |
| if (status != ERROR_IO_PENDING) |
| return 0; |
| /* wait for completion with timeout */ |
| status = WaitForSingleObject(overlapped.hEvent, timeout); |
| if (status == WAIT_TIMEOUT) |
| CancelIo(musb_interface->rhandle); |
| else |
| GetOverlappedResult(musb_interface->rhandle, &overlapped, &n_read, FALSE); |
| } |
| CloseHandle(overlapped.hEvent); |
| #endif |
| //fprintf(stderr, "musb_read(ep %d, %d bytes) returns %d (%s)\n", endpoint, count, n_read, buf); |
| return n_read; |
| } |
| int musb_reset(MUSB_INTERFACE *musb_interface) |
| { |
| #if defined(HAVE_LIBUSB) |
| /* Causes re-enumeration: After calling usb_reset, the device will need |
| to re-enumerate and thusly, requires you to find the new device and |
| open a new handle. The handle used to call usb_reset will no longer work */ |
| int status; |
| status = usb_reset(musb_interface->dev); |
| if (status < 0) |
| fprintf(stderr, "musb_reset: usb_reset() status %d\n", status); |
| #elif defined(HAVE_LIBUSB10) |
| int status; |
| status = libusb_reset_device(musb_interface->dev); |
| if (status < 0) |
| fprintf(stderr, "musb_reset: usb_reset() status %d\n", status); |
| #elif defined(OS_DARWIN) |
| IOReturn status; |
| IOUSBDeviceInterface **device = (IOUSBDeviceInterface**)musb_interface->device; |
| status = (*device)->ResetDevice(device); |
| fprintf(stderr, "musb_reset: ResetDevice() status 0x%x\n", status); |
| status = darwin_configure_device(musb_interface); |
| assert(status == kIOReturnSuccess); |
| #elif defined(_MSC_VER) |
| #define IOCTL_BULKUSB_RESET_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, \ |
| 1, \ |
| METHOD_BUFFERED, \ |
| FILE_ANY_ACCESS) |
| #define IOCTL_BULKUSB_RESET_PIPE CTL_CODE(FILE_DEVICE_UNKNOWN, \ |
| 2, \ |
| METHOD_BUFFERED, \ |
| FILE_ANY_ACCESS) |
| int status, n_bytes; |
| status = DeviceIoControl(musb_interface->rhandle, |
| IOCTL_BULKUSB_RESET_DEVICE, |
| NULL, 0, NULL, 0, &n_bytes, NULL); |
| status = DeviceIoControl(musb_interface->whandle, |
| IOCTL_BULKUSB_RESET_DEVICE, |
| NULL, 0, NULL, 0, &n_bytes, NULL); |
| status = DeviceIoControl(musb_interface->rhandle, |
| IOCTL_BULKUSB_RESET_PIPE, |
| NULL, 0, NULL, 0, &n_bytes, NULL); |
| status = DeviceIoControl(musb_interface->whandle, |
| IOCTL_BULKUSB_RESET_PIPE, |
| NULL, 0, NULL, 0, &n_bytes, NULL); |
| return status; |
| #endif |
| return 0; |
| } |
| int musb_get_device(MUSB_INTERFACE *usb_interface) |
| { |
| #ifdef HAVE_LIBUSB |
| struct usb_device_descriptor d; |
| usb_get_descriptor(usb_interface->dev, USB_DT_DEVICE, 0, &d, sizeof(d)); |
| return d.bcdDevice; |
| #elif HAVE_LIBUSB10 |
| struct libusb_device_descriptor d; |
| libusb_get_descriptor(usb_interface->dev, LIBUSB_DT_DEVICE, 0, (unsigned char *)&d, sizeof(d)); |
| return d.bcdDevice; |
| #else |
| return 0; |
| #endif |
| } |
| /* end */ |
| /cvi/instr/drsctrl/musbstd.h |
|---|
| 0,0 → 1,95 |
| /********************************************************************\ |
| Name: musbstd.h |
| Created by: Konstantin Olchanski, Stefan Ritt |
| Contents: Midas USB access |
| $Id$ |
| \********************************************************************/ |
| #ifndef MUSBSTD_H |
| #define MUSBSTD_H |
| #if defined(HAVE_LIBUSB) |
| #include "usb.h" |
| typedef struct { |
| usb_dev_handle *dev; |
| int usb_configuration; |
| int usb_interface; |
| int usb_type; |
| } MUSB_INTERFACE; |
| #elif defined(HAVE_LIBUSB10) |
| #include <libusb-1.0/libusb.h> |
| typedef struct { |
| libusb_device_handle *dev; |
| int usb_configuration; |
| int usb_interface; |
| int usb_type; |
| } MUSB_INTERFACE; |
| #elif defined(_MSC_VER) |
| #include <windows.h> |
| typedef struct { |
| HANDLE rhandle; |
| HANDLE whandle; |
| int usb_type; |
| } MUSB_INTERFACE; |
| #elif defined(OS_DARWIN) |
| typedef struct { |
| void *device; |
| void *interface; |
| int usb_configuration; |
| int usb_interface; |
| int usb_type; |
| } MUSB_INTERFACE; |
| #else |
| #error Do not know how to access USB devices |
| #endif |
| /*---- status codes ------------------------------------------------*/ |
| #define MUSB_SUCCESS 1 |
| #define MUSB_NOT_FOUND 2 |
| #define MUSB_INVALID_PARAM 3 |
| #define MUSB_NO_MEM 4 |
| #define MUSB_ACCESS_ERROR 5 |
| /* make functions callable from a C++ program */ |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| /* make functions under WinNT dll exportable */ |
| #ifndef EXPRT |
| #if defined(_MSC_VER) && defined(_USRDLL) |
| #define EXPRT __declspec(dllexport) |
| #else |
| #define EXPRT |
| #endif |
| #endif |
| int EXPRT musb_open(MUSB_INTERFACE **musb_interface, int vendor, int product, int instance, int configuration, int usbinterface); |
| int EXPRT musb_close(MUSB_INTERFACE *musb_interface); |
| int EXPRT musb_write(MUSB_INTERFACE *musb_interface,int endpoint,const void *buf,int count,int timeout_ms); |
| int EXPRT musb_read(MUSB_INTERFACE *musb_interface,int endpoint,void *buf,int count,int timeout_ms); |
| int EXPRT musb_reset(MUSB_INTERFACE *musb_interface); |
| int EXPRT musb_set_altinterface(MUSB_INTERFACE *musb_interface, int index); |
| int EXPRT musb_get_device(MUSB_INTERFACE *musb_interface); |
| #ifdef __cplusplus |
| } |
| #endif |
| #endif // MUSBSTD_H |
| /cvi/instr/drsctrl/musbstd.obj |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |
| /cvi/instr/drsctrl/mxml.c |
|---|
| 0,0 → 1,2366 |
| /********************************************************************\ |
| Name: mxml.c |
| Created by: Stefan Ritt |
| Copyright 2000 + Stefan Ritt |
| Contents: Midas XML Library |
| This is a simple implementation of XML functions for writing and |
| reading XML files. For writing an XML file from scratch, following |
| functions can be used: |
| writer = mxml_open_file(file_name); |
| mxml_start_element(writer, name); |
| mxml_write_attribute(writer, name, value); |
| mxml_write_value(writer, value); |
| mxml_end_element(writer); |
| ... |
| mxml_close_file(writer); |
| To read an XML file, the function |
| tree = mxml_parse_file(file_name, error, sizeof(error)); |
| is used. It parses the complete XML file and stores it in a |
| hierarchical tree in memory. Nodes in that tree can be searched |
| for with |
| mxml_find_node(tree, xml_path); |
| or |
| mxml_find_nodes(tree, xml_path, &nodelist); |
| which support a subset of the XPath specification. Another set of |
| functions is availabe to retrieve attributes and values from nodes |
| in the tree and for manipulating nodes, like replacing, adding and |
| deleting nodes. |
| This file is part of MIDAS XML Library. |
| MIDAS XML Library is free software: you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| MIDAS XML Library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| You should have received a copy of the GNU General Public License |
| along with MIDAS XML Library. If not, see <http://www.gnu.org/licenses/>. |
| \********************************************************************/ |
| #include <stdio.h> |
| #include <fcntl.h> |
| #include <string.h> |
| #include <assert.h> |
| #ifdef _MSC_VER |
| #include <windows.h> |
| #include <io.h> |
| #include <time.h> |
| #pragma warning( disable: 4996) /* disable "deprecated" warning */ |
| #else |
| #define TRUE 1 |
| #define FALSE 0 |
| #ifndef O_TEXT |
| #define O_TEXT 0 |
| #define O_BINARY 0 |
| #endif |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <ctype.h> |
| #include <stdarg.h> |
| #include <errno.h> |
| #ifndef OS_VXWORKS |
| #include <sys/time.h> |
| #endif |
| #include <time.h> |
| #endif |
| #include "mxml.h" |
| #ifndef HAVE_STRLCPY |
| #include "strlcpy.h" |
| #endif |
| #define XML_INDENT " " |
| #if defined(__GNUC__) && !defined(__MAKECINT__) |
| # define MXML_GNUC_PRINTF( format_idx, arg_idx ) \ |
| __attribute__((format (printf, format_idx, arg_idx))) |
| # define MXML_GNUC_SCANF( format_idx, arg_idx ) \ |
| __attribute__((format (scanf, format_idx, arg_idx))) |
| # define MXML_GNUC_FORMAT( arg_idx ) \ |
| __attribute__((format_arg (arg_idx))) |
| #else |
| # define MXML_GNUC_PRINTF( format_idx, arg_idx ) |
| # define MXML_GNUC_SCANF( format_idx, arg_idx ) |
| # define MXML_GNUC_FORMAT( arg_idx ) |
| #endif |
| static int mxml_suppress_date_flag = 0; /* suppress writing date at the top of file. */ |
| /* local prototypes */ |
| static PMXML_NODE read_error(PMXML_NODE root, const char *file_name, int line_number, char *error, int error_size, int *error_line, const char *format, ...) MXML_GNUC_PRINTF(7, 8); |
| static void mxml_encode(char *src, int size, int translate); |
| static void mxml_decode(char *str); |
| static int mxml_write_subtree(MXML_WRITER *writer, PMXML_NODE tree, int indent); |
| static int mxml_write_line(MXML_WRITER *writer, const char *line); |
| static int mxml_start_element1(MXML_WRITER *writer, const char *name, int indent); |
| static int mxml_add_resultnode(PMXML_NODE node, const char *xml_path, PMXML_NODE **nodelist, int *found); |
| static int mxml_find_nodes1(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist, int *found); |
| static void *mxml_malloc(size_t size); |
| static void *mxml_realloc(void *p, size_t size); |
| static void mxml_free(void *p); |
| static void mxml_deallocate(void); |
| /*------------------------------------------------------------------*/ |
| static char *_encode_buffer = NULL; |
| static char *_data_enc = NULL; |
| /*------------------------------------------------------------------*/ |
| void *mxml_malloc(size_t size) |
| { |
| return malloc(size); |
| } |
| /*------------------------------------------------------------------*/ |
| void *mxml_realloc(void *p, size_t size) |
| { |
| return realloc(p, size); |
| } |
| /*------------------------------------------------------------------*/ |
| void mxml_free(void *p) |
| { |
| free(p); |
| } |
| /*------------------------------------------------------------------*/ |
| void mxml_deallocate(void) |
| { |
| if (_encode_buffer != NULL) { |
| mxml_free(_encode_buffer); |
| _encode_buffer = NULL; |
| } |
| if (_data_enc != NULL) { |
| mxml_free(_data_enc); |
| _data_enc = NULL; |
| } |
| } |
| /*------------------------------------------------------------------*/ |
| int mxml_write_line(MXML_WRITER *writer, const char *line) |
| { |
| int len; |
| len = (int)strlen(line); |
| if (writer->buffer) { |
| if (writer->buffer_len + len >= writer->buffer_size) { |
| writer->buffer_size += 10000; |
| writer->buffer = (char *)mxml_realloc(writer->buffer, writer->buffer_size); |
| } |
| strcpy(writer->buffer + writer->buffer_len, line); |
| writer->buffer_len += len; |
| return len; |
| } else { |
| return (int)write(writer->fh, line, len); |
| } |
| return 0; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * open a memory buffer and write XML header |
| */ |
| MXML_WRITER *mxml_open_buffer(void) |
| { |
| char str[256], line[1000]; |
| time_t now; |
| MXML_WRITER *writer; |
| writer = (MXML_WRITER *)mxml_malloc(sizeof(MXML_WRITER)); |
| memset(writer, 0, sizeof(MXML_WRITER)); |
| writer->translate = 1; |
| writer->buffer_size = 10000; |
| writer->buffer = (char *)mxml_malloc(10000); |
| writer->buffer[0] = 0; |
| writer->buffer_len = 0; |
| /* write XML header */ |
| strcpy(line, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"); |
| mxml_write_line(writer, line); |
| time(&now); |
| strcpy(str, ctime(&now)); |
| str[24] = 0; |
| sprintf(line, "<!-- created by MXML on %s -->\n", str); |
| if (mxml_suppress_date_flag == 0) |
| mxml_write_line(writer, line); |
| /* initialize stack */ |
| writer->level = 0; |
| writer->element_is_open = 0; |
| return writer; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * suppress writing date at the top of file. |
| */ |
| void mxml_suppress_date(int suppress) |
| { |
| mxml_suppress_date_flag = suppress; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * open a file and write XML header |
| */ |
| MXML_WRITER *mxml_open_file(const char *file_name) |
| { |
| char str[256], line[1000]; |
| time_t now; |
| MXML_WRITER *writer; |
| writer = (MXML_WRITER *)mxml_malloc(sizeof(MXML_WRITER)); |
| memset(writer, 0, sizeof(MXML_WRITER)); |
| writer->translate = 1; |
| writer->fh = open(file_name, O_RDWR | O_CREAT | O_TRUNC | O_TEXT, 0644); |
| if (writer->fh == -1) { |
| sprintf(line, "Unable to open file \"%s\": ", file_name); |
| perror(line); |
| mxml_free(writer); |
| return NULL; |
| } |
| /* write XML header */ |
| strcpy(line, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"); |
| mxml_write_line(writer, line); |
| time(&now); |
| strcpy(str, ctime(&now)); |
| str[24] = 0; |
| sprintf(line, "<!-- created by MXML on %s -->\n", str); |
| if (mxml_suppress_date_flag == 0) |
| mxml_write_line(writer, line); |
| /* initialize stack */ |
| writer->level = 0; |
| writer->element_is_open = 0; |
| return writer; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * convert '<' '>' '&' '"' ''' into &xx; |
| */ |
| void mxml_encode(char *src, int size, int translate) |
| { |
| char *ps, *pd; |
| static int buffer_size = 1000; |
| assert(size); |
| if (_encode_buffer == NULL) { |
| _encode_buffer = (char *) mxml_malloc(buffer_size); |
| atexit(mxml_deallocate); |
| } |
| if (size > buffer_size) { |
| _encode_buffer = (char *) mxml_realloc(_encode_buffer, size*2); |
| buffer_size = size; |
| } |
| pd = _encode_buffer; |
| for (ps = src ; *ps && (size_t)pd - (size_t)_encode_buffer < (size_t)(size-10) ; ps++) { |
| if (translate) { /* tranlate "<", ">", "&", """, "'" */ |
| switch (*ps) { |
| case '<': |
| strcpy(pd, "<"); |
| pd += 4; |
| break; |
| case '>': |
| strcpy(pd, ">"); |
| pd += 4; |
| break; |
| case '&': |
| strcpy(pd, "&"); |
| pd += 5; |
| break; |
| case '\"': |
| strcpy(pd, """); |
| pd += 6; |
| break; |
| case '\'': |
| strcpy(pd, "'"); |
| pd += 6; |
| break; |
| default: |
| *pd++ = *ps; |
| } |
| } else { |
| switch (*ps) { /* translate only illegal XML characters "<" and "&" */ |
| case '<': |
| strcpy(pd, "<"); |
| pd += 4; |
| break; |
| case '&': |
| strcpy(pd, "&"); |
| pd += 5; |
| break; |
| default: |
| *pd++ = *ps; |
| } |
| } |
| } |
| *pd = 0; |
| strlcpy(src, _encode_buffer, size); |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * reverse of mxml_encode, strip leading or trailing '"' |
| */ |
| void mxml_decode(char *str) |
| { |
| char *p; |
| p = str; |
| while ((p = strchr(p, '&')) != NULL) { |
| if (strncmp(p, "<", 4) == 0) { |
| *(p++) = '<'; |
| memmove(p, p+3, strlen(p+3) + 1); |
| } |
| else if (strncmp(p, ">", 4) == 0) { |
| *(p++) = '>'; |
| memmove(p, p+3, strlen(p+3) + 1); |
| } |
| else if (strncmp(p, "&", 5) == 0) { |
| *(p++) = '&'; |
| memmove(p, p+4, strlen(p+4) + 1); |
| } |
| else if (strncmp(p, """, 6) == 0) { |
| *(p++) = '\"'; |
| memmove(p, p+5, strlen(p+5) + 1); |
| } |
| else if (strncmp(p, "'", 6) == 0) { |
| *(p++) = '\''; |
| memmove(p, p+5, strlen(p+5) + 1); |
| } |
| else { |
| p++; // skip unknown entity |
| } |
| } |
| /* if (str[0] == '\"' && str[strlen(str)-1] == '\"') { |
| memmove(str, str+1, strlen(str+1) + 1); |
| str[strlen(str)-1] = 0; |
| }*/ |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * set translation of <,>,",',&, on/off in writer |
| */ |
| int mxml_set_translate(MXML_WRITER *writer, int flag) |
| { |
| int old_flag; |
| old_flag = writer->translate; |
| writer->translate = flag; |
| return old_flag; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * start a new XML element, must be followed by mxml_end_elemnt |
| */ |
| int mxml_start_element1(MXML_WRITER *writer, const char *name, int indent) |
| { |
| int i; |
| char line[1000], name_enc[1000]; |
| if (writer->element_is_open) { |
| mxml_write_line(writer, ">\n"); |
| writer->element_is_open = FALSE; |
| } |
| line[0] = 0; |
| if (indent) |
| for (i=0 ; i<writer->level ; i++) |
| strlcat(line, XML_INDENT, sizeof(line)); |
| strlcat(line, "<", sizeof(line)); |
| strlcpy(name_enc, name, sizeof(name_enc)); |
| mxml_encode(name_enc, sizeof(name_enc), writer->translate); |
| strlcat(line, name_enc, sizeof(line)); |
| /* put element on stack */ |
| if (writer->level == 0) |
| writer->stack = (char **)mxml_malloc(sizeof(char *)); |
| else |
| writer->stack = (char **)mxml_realloc(writer->stack, sizeof(char *)*(writer->level+1)); |
| writer->stack[writer->level] = (char *) mxml_malloc(strlen(name_enc)+1); |
| strcpy(writer->stack[writer->level], name_enc); |
| writer->level++; |
| writer->element_is_open = TRUE; |
| writer->data_was_written = FALSE; |
| return mxml_write_line(writer, line) == (int)strlen(line); |
| } |
| /*------------------------------------------------------------------*/ |
| int mxml_start_element(MXML_WRITER *writer, const char *name) |
| { |
| return mxml_start_element1(writer, name, TRUE); |
| } |
| /*------------------------------------------------------------------*/ |
| int mxml_start_element_noindent(MXML_WRITER *writer, const char *name) |
| { |
| return mxml_start_element1(writer, name, FALSE); |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * close an open XML element |
| */ |
| int mxml_end_element(MXML_WRITER *writer) |
| { |
| int i; |
| char line[1000]; |
| if (writer->level == 0) |
| return 0; |
| writer->level--; |
| if (writer->element_is_open) { |
| writer->element_is_open = FALSE; |
| mxml_free(writer->stack[writer->level]); |
| if (writer->level == 0) |
| mxml_free(writer->stack); |
| strcpy(line, "/>\n"); |
| return mxml_write_line(writer, line) == (int)strlen(line); |
| } |
| line[0] = 0; |
| if (!writer->data_was_written) { |
| for (i=0 ; i<writer->level ; i++) |
| strlcat(line, XML_INDENT, sizeof(line)); |
| } |
| strlcat(line, "</", sizeof(line)); |
| strlcat(line, writer->stack[writer->level], sizeof(line)); |
| mxml_free(writer->stack[writer->level]); |
| if (writer->level == 0) |
| mxml_free(writer->stack); |
| strlcat(line, ">\n", sizeof(line)); |
| writer->data_was_written = FALSE; |
| return mxml_write_line(writer, line) == (int)strlen(line); |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * write an attribute to the currently open XML element |
| */ |
| int mxml_write_attribute(MXML_WRITER *writer, const char *name, const char *value) |
| { |
| char name_enc[4096], val_enc[4096], line[8192]; |
| if (!writer->element_is_open) |
| return FALSE; |
| strcpy(name_enc, name); |
| mxml_encode(name_enc, sizeof(name_enc), writer->translate); |
| strcpy(val_enc, value); |
| mxml_encode(val_enc, sizeof(val_enc), writer->translate); |
| sprintf(line, " %s=\"%s\"", name_enc, val_enc); |
| return mxml_write_line(writer, line) == (int)strlen(line); |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * write value of an XML element, like <[name]>[value]</[name]> |
| */ |
| int mxml_write_value(MXML_WRITER *writer, const char *data) |
| { |
| static int data_size = 0; |
| if (!writer->element_is_open) |
| return FALSE; |
| if (mxml_write_line(writer, ">") != 1) |
| return FALSE; |
| writer->element_is_open = FALSE; |
| writer->data_was_written = TRUE; |
| if (data_size == 0) { |
| _data_enc = (char *)mxml_malloc(1000); |
| data_size = 1000; |
| } else if ((int)strlen(data)*2+1000 > data_size) { |
| data_size = 1000+(int)strlen(data)*2; |
| _data_enc = (char *)mxml_realloc(_data_enc, data_size); |
| } |
| strcpy(_data_enc, data); |
| mxml_encode(_data_enc, data_size, writer->translate); |
| return mxml_write_line(writer, _data_enc) == (int)strlen(_data_enc); |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * write empty line |
| */ |
| int mxml_write_empty_line(MXML_WRITER *writer) |
| { |
| if (writer->element_is_open) { |
| mxml_write_line(writer, ">\n"); |
| writer->element_is_open = FALSE; |
| } |
| if (mxml_write_line(writer, "\n") != 1) |
| return FALSE; |
| return TRUE; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * write a comment to an XML file, enclosed in "<!--" and "-->" |
| */ |
| int mxml_write_comment(MXML_WRITER *writer, const char *string) |
| { |
| int i; |
| char line[1000]; |
| if (writer->element_is_open) { |
| mxml_write_line(writer, ">\n"); |
| writer->element_is_open = FALSE; |
| } |
| line[0] = 0; |
| for (i=0 ; i<writer->level ; i++) |
| strlcat(line, XML_INDENT, sizeof(line)); |
| strlcat(line, "<!-- ", sizeof(line)); |
| strlcat(line, string, sizeof(line)); |
| strlcat(line, " -->\n", sizeof(line)); |
| if (mxml_write_line(writer, line) != (int)strlen(line)) |
| return FALSE; |
| return TRUE; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * shortcut to write an element with a value but without attribute |
| */ |
| int mxml_write_element(MXML_WRITER *writer, const char *name, const char *value) |
| { |
| int i; |
| i = mxml_start_element(writer, name); |
| i += mxml_write_value(writer, value); |
| i += mxml_end_element(writer); |
| return i; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * close a file opened with mxml_open_writer |
| */ |
| char *mxml_close_buffer(MXML_WRITER *writer) |
| { |
| int i; |
| char *p; |
| if (writer->element_is_open) { |
| writer->element_is_open = FALSE; |
| if (mxml_write_line(writer, ">\n") != 2) |
| return NULL; |
| } |
| /* close remaining open levels */ |
| for (i = 0 ; i<writer->level ; i++) |
| mxml_end_element(writer); |
| p = writer->buffer; |
| mxml_free(writer); |
| return p; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * close a file opened with mxml_open_writer |
| */ |
| int mxml_close_file(MXML_WRITER *writer) |
| { |
| int i; |
| if (writer->element_is_open) { |
| writer->element_is_open = FALSE; |
| if (mxml_write_line(writer, ">\n") != 2) |
| return 0; |
| } |
| /* close remaining open levels */ |
| for (i = 0 ; i<writer->level ; i++) |
| mxml_end_element(writer); |
| close(writer->fh); |
| mxml_free(writer); |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * create root node of an XML tree |
| */ |
| PMXML_NODE mxml_create_root_node(void) |
| { |
| PMXML_NODE root; |
| root = (PMXML_NODE)calloc(sizeof(MXML_NODE), 1); |
| strcpy(root->name, "root"); |
| root->node_type = DOCUMENT_NODE; |
| return root; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * add a subnode (child) to an existing parent node as a specific position |
| */ |
| PMXML_NODE mxml_add_special_node_at(PMXML_NODE parent, int node_type, const char *node_name, const char *value, int idx) |
| { |
| PMXML_NODE pnode, pchild; |
| int i, j; |
| assert(parent); |
| if (parent->n_children == 0) |
| parent->child = (PMXML_NODE)mxml_malloc(sizeof(MXML_NODE)); |
| else |
| parent->child = (PMXML_NODE)mxml_realloc(parent->child, sizeof(MXML_NODE)*(parent->n_children+1)); |
| assert(parent->child); |
| /* move following nodes one down */ |
| if (idx < parent->n_children) |
| for (i=parent->n_children ; i > idx ; i--) |
| memcpy(&parent->child[i], &parent->child[i-1], sizeof(MXML_NODE)); |
| /* correct parent pointer for children */ |
| for (i=0 ; i<parent->n_children ; i++) { |
| pchild = parent->child+i; |
| for (j=0 ; j<pchild->n_children ; j++) |
| pchild->child[j].parent = pchild; |
| } |
| /* initialize new node */ |
| pnode = &parent->child[idx]; |
| memset(pnode, 0, sizeof(MXML_NODE)); |
| strlcpy(pnode->name, node_name, sizeof(pnode->name)); |
| pnode->node_type = node_type; |
| pnode->parent = parent; |
| parent->n_children++; |
| if (value && *value) { |
| pnode->value = (char *)mxml_malloc(strlen(value)+1); |
| assert(pnode->value); |
| strcpy(pnode->value, value); |
| } |
| return pnode; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * add a subnode (child) to an existing parent node at the end |
| */ |
| PMXML_NODE mxml_add_special_node(PMXML_NODE parent, int node_type, const char *node_name, const char *value) |
| { |
| return mxml_add_special_node_at(parent, node_type, node_name, value, parent->n_children); |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * write value of an XML element, like <[name]>[value]</[name]> |
| */ |
| PMXML_NODE mxml_add_node(PMXML_NODE parent, const char *node_name, const char *value) |
| { |
| return mxml_add_special_node_at(parent, ELEMENT_NODE, node_name, value, parent->n_children); |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * add a subnode (child) to an existing parent node at the end |
| */ |
| PMXML_NODE mxml_add_node_at(PMXML_NODE parent, const char *node_name, const char *value, int idx) |
| { |
| return mxml_add_special_node_at(parent, ELEMENT_NODE, node_name, value, idx); |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * add a whole node tree to an existing parent node at a specific position |
| */ |
| int mxml_add_tree_at(PMXML_NODE parent, PMXML_NODE tree, int idx) |
| { |
| PMXML_NODE pchild; |
| int i, j, k; |
| assert(parent); |
| assert(tree); |
| if (parent->n_children == 0) |
| parent->child = (PMXML_NODE)mxml_malloc(sizeof(MXML_NODE)); |
| else { |
| pchild = parent->child; |
| parent->child = (PMXML_NODE)mxml_realloc(parent->child, sizeof(MXML_NODE)*(parent->n_children+1)); |
| if (parent->child != pchild) { |
| /* correct parent pointer for children */ |
| for (i=0 ; i<parent->n_children ; i++) { |
| pchild = parent->child+i; |
| for (j=0 ; j<pchild->n_children ; j++) |
| pchild->child[j].parent = pchild; |
| } |
| } |
| } |
| assert(parent->child); |
| if (idx < parent->n_children) |
| for (i=parent->n_children ; i > idx ; i--) { |
| /* move following nodes one down */ |
| memcpy(&parent->child[i], &parent->child[i-1], sizeof(MXML_NODE)); |
| /* correct parent pointer for children */ |
| for (j=0 ; j<parent->n_children ; j++) { |
| pchild = parent->child+j; |
| for (k=0 ; k<pchild->n_children ; k++) |
| pchild->child[k].parent = pchild; |
| } |
| } |
| /* initialize new node */ |
| memcpy(parent->child+idx, tree, sizeof(MXML_NODE)); |
| parent->n_children++; |
| parent->child[idx].parent = parent; |
| /* correct parent pointer for children */ |
| for (i=0 ; i<parent->n_children ; i++) { |
| pchild = parent->child+i; |
| for (j=0 ; j<pchild->n_children ; j++) |
| pchild->child[j].parent = pchild; |
| } |
| return TRUE; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * add a whole node tree to an existing parent node at the end |
| */ |
| int mxml_add_tree(PMXML_NODE parent, PMXML_NODE tree) |
| { |
| return mxml_add_tree_at(parent, tree, parent->n_children); |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * add an attribute to an existing node |
| */ |
| int mxml_add_attribute(PMXML_NODE pnode, const char *attrib_name, const char *attrib_value) |
| { |
| if (pnode->n_attributes == 0) { |
| pnode->attribute_name = (char*)mxml_malloc(MXML_NAME_LENGTH); |
| pnode->attribute_value = (char**)mxml_malloc(sizeof(char *)); |
| } else { |
| pnode->attribute_name = (char*)mxml_realloc(pnode->attribute_name, MXML_NAME_LENGTH*(pnode->n_attributes+1)); |
| pnode->attribute_value = (char**)mxml_realloc(pnode->attribute_value, sizeof(char *)*(pnode->n_attributes+1)); |
| } |
| strlcpy(pnode->attribute_name+pnode->n_attributes*MXML_NAME_LENGTH, attrib_name, MXML_NAME_LENGTH); |
| pnode->attribute_value[pnode->n_attributes] = (char *)mxml_malloc(strlen(attrib_value)+1); |
| strcpy(pnode->attribute_value[pnode->n_attributes], attrib_value); |
| pnode->n_attributes++; |
| return TRUE; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * return number of subnodes (children) of a node |
| */ |
| int mxml_get_number_of_children(PMXML_NODE pnode) |
| { |
| assert(pnode); |
| return pnode->n_children; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * return number of subnodes (children) of a node |
| */ |
| PMXML_NODE mxml_subnode(PMXML_NODE pnode, int idx) |
| { |
| assert(pnode); |
| if (idx < pnode->n_children) |
| return &pnode->child[idx]; |
| return NULL; |
| } |
| /*------------------------------------------------------------------*/ |
| int mxml_find_nodes1(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist, int *found); |
| int mxml_add_resultnode(PMXML_NODE node, const char *xml_path, PMXML_NODE **nodelist, int *found) |
| { |
| /* if at end of path, add this node */ |
| if (*xml_path == 0) { |
| if (*found == 0) |
| *nodelist = (PMXML_NODE *)mxml_malloc(sizeof(PMXML_NODE)); |
| else |
| *nodelist = (PMXML_NODE *)mxml_realloc(*nodelist, sizeof(PMXML_NODE)*(*found + 1)); |
| (*nodelist)[*found] = node; |
| (*found)++; |
| } else { |
| /* if not at end of path, branch into subtree */ |
| return mxml_find_nodes1(node, xml_path+1, nodelist, found); |
| } |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| Return list of XML nodes with a subset of XPATH specifications. |
| Following elemets are possible |
| /<node>/<node>/..../<node> Find a node in the tree hierarchy |
| /<node>[idx] Find child #[idx] of node (index starts from 1) |
| /<node>[idx]/<node> Find subnode of the above |
| /<node>[<subnode>=<value>] Find a node which has a specific subnode |
| /<node>[<subnode>=<value>]/<node> Find subnode of the above |
| /<node>[@<attrib>=<value>]/<node> Find a node which has a specific attribute |
| */ |
| int mxml_find_nodes1(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist, int *found) |
| { |
| PMXML_NODE pnode; |
| const char *p1,*p2; |
| char *p3, node_name[256], condition[256]; |
| char cond_name[MXML_MAX_CONDITION][256], cond_value[MXML_MAX_CONDITION][256]; |
| int cond_type[MXML_MAX_CONDITION]; |
| int i, j, k, idx, num_cond; |
| int cond_satisfied,cond_index; |
| size_t len; |
| p1 = xml_path; |
| pnode = tree; |
| /* skip leading '/' */ |
| if (*p1 && *p1 == '/') |
| p1++; |
| do { |
| p2 = p1; |
| while (*p2 && *p2 != '/' && *p2 != '[') |
| p2++; |
| len = (size_t)p2 - (size_t)p1; |
| if (len >= sizeof(node_name)) |
| return 0; |
| memcpy(node_name, p1, len); |
| node_name[len] = 0; |
| idx = 0; |
| num_cond = 0; |
| while (*p2 == '[') { |
| cond_name[num_cond][0] = cond_value[num_cond][0] = cond_type[num_cond] = 0; |
| p2++; |
| if (isdigit(*p2)) { |
| /* evaluate [idx] */ |
| idx = atoi(p2); |
| p2 = strchr(p2, ']'); |
| if (p2 == NULL) |
| return 0; |
| p2++; |
| } else { |
| /* evaluate [<@attrib>/<subnode>=<value>] */ |
| while (*p2 && isspace((unsigned char)*p2)) |
| p2++; |
| strlcpy(condition, p2, sizeof(condition)); |
| if (strchr(condition, ']')) |
| *strchr(condition, ']') = 0; |
| else |
| return 0; |
| p2 = strchr(p2, ']')+1; |
| if ((p3 = strchr(condition, '=')) != NULL) { |
| if (condition[0] == '@') { |
| cond_type[num_cond] = 1; |
| strlcpy(cond_name[num_cond], &condition[1], sizeof(cond_name[num_cond])); |
| } else { |
| strlcpy(cond_name[num_cond], condition, sizeof(cond_name[num_cond])); |
| } |
| *strchr(cond_name[num_cond], '=') = 0; |
| while (cond_name[num_cond][0] && isspace(cond_name[num_cond][strlen(cond_name[num_cond])-1])) |
| cond_name[num_cond][strlen(cond_name[num_cond])-1] = 0; |
| p3++; |
| while (*p3 && isspace(*p3)) |
| p3++; |
| if (*p3 == '\"') { |
| strlcpy(cond_value[num_cond], p3+1, sizeof(cond_value[num_cond])); |
| while (cond_value[num_cond][0] && isspace(cond_value[num_cond][strlen(cond_value[num_cond])-1])) |
| cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0; |
| if (cond_value[num_cond][0] && cond_value[num_cond][strlen(cond_value[num_cond])-1] == '\"') |
| cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0; |
| } else if (*p3 == '\'') { |
| strlcpy(cond_value[num_cond], p3+1, sizeof(cond_value[num_cond])); |
| while (cond_value[num_cond][0] && isspace(cond_value[num_cond][strlen(cond_value[num_cond])-1])) |
| cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0; |
| if (cond_value[num_cond][0] && cond_value[num_cond][strlen(cond_value[num_cond])-1] == '\'') |
| cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0; |
| } else { |
| strlcpy(cond_value[num_cond], p3, sizeof(cond_value[num_cond])); |
| while (cond_value[num_cond][0] && isspace(cond_value[num_cond][strlen(cond_value[num_cond])-1])) |
| cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0; |
| } |
| num_cond++; |
| } |
| } |
| } |
| cond_index = 0; |
| for (i=j=0 ; i<pnode->n_children ; i++) { |
| if (num_cond) { |
| cond_satisfied = 0; |
| for (k=0;k<num_cond;k++) { |
| if (cond_type[k]) { |
| /* search node with attribute */ |
| if (strcmp(pnode->child[i].name, node_name) == 0) |
| if (mxml_get_attribute(pnode->child+i, cond_name[k]) && |
| strcmp(mxml_get_attribute(pnode->child+i, cond_name[k]), cond_value[k]) == 0) |
| cond_satisfied++; |
| } |
| else { |
| /* search subnode */ |
| for (j=0 ; j<pnode->child[i].n_children ; j++) |
| if (strcmp(pnode->child[i].child[j].name, cond_name[k]) == 0) |
| if (strcmp(pnode->child[i].child[j].value, cond_value[k]) == 0) |
| cond_satisfied++; |
| } |
| } |
| if (cond_satisfied==num_cond) { |
| cond_index++; |
| if (idx == 0 || cond_index == idx) { |
| if (!mxml_add_resultnode(pnode->child+i, p2, nodelist, found)) |
| return 0; |
| } |
| } |
| } else { |
| if (strcmp(pnode->child[i].name, node_name) == 0) |
| if (idx == 0 || ++j == idx) |
| if (!mxml_add_resultnode(pnode->child+i, p2, nodelist, found)) |
| return 0; |
| } |
| } |
| if (i == pnode->n_children) |
| return 1; |
| pnode = &pnode->child[i]; |
| p1 = p2; |
| if (*p1 == '/') |
| p1++; |
| } while (*p2); |
| return 1; |
| } |
| /*------------------------------------------------------------------*/ |
| int mxml_find_nodes(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist) |
| { |
| int status, found = 0; |
| status = mxml_find_nodes1(tree, xml_path, nodelist, &found); |
| if (status == 0) |
| return -1; |
| return found; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * Search for a specific XML node with a subset of XPATH specifications. |
| * Return first found node. For syntax see mxml_find_nodes() |
| */ |
| PMXML_NODE mxml_find_node(PMXML_NODE tree, const char *xml_path) |
| { |
| PMXML_NODE *node, pnode; |
| int n; |
| n = mxml_find_nodes(tree, xml_path, &node); |
| if (n > 0) { |
| pnode = node[0]; |
| mxml_free(node); |
| } else |
| pnode = NULL; |
| return pnode; |
| } |
| /*------------------------------------------------------------------*/ |
| PMXML_NODE mxml_get_parent(PMXML_NODE pnode) |
| { |
| assert(pnode); |
| return pnode->parent; |
| } |
| /*------------------------------------------------------------------*/ |
| char *mxml_get_name(PMXML_NODE pnode) |
| { |
| assert(pnode); |
| return pnode->name; |
| } |
| /*------------------------------------------------------------------*/ |
| char *mxml_get_value(PMXML_NODE pnode) |
| { |
| assert(pnode); |
| return pnode->value; |
| } |
| /*------------------------------------------------------------------*/ |
| int mxml_get_line_number_start(PMXML_NODE pnode) |
| { |
| assert(pnode); |
| return pnode->line_number_start; |
| } |
| /*------------------------------------------------------------------*/ |
| int mxml_get_line_number_end(PMXML_NODE pnode) |
| { |
| assert(pnode); |
| return pnode->line_number_end; |
| } |
| /*------------------------------------------------------------------*/ |
| char *mxml_get_attribute(PMXML_NODE pnode, const char *name) |
| { |
| int i; |
| assert(pnode); |
| for (i=0 ; i<pnode->n_attributes ; i++) |
| if (strcmp(pnode->attribute_name+i*MXML_NAME_LENGTH, name) == 0) |
| return pnode->attribute_value[i]; |
| return NULL; |
| } |
| /*------------------------------------------------------------------*/ |
| int mxml_replace_node_name(PMXML_NODE pnode, const char *name) |
| { |
| strlcpy(pnode->name, name, sizeof(pnode->name)); |
| return TRUE; |
| } |
| /*------------------------------------------------------------------*/ |
| int mxml_replace_node_value(PMXML_NODE pnode, const char *value) |
| { |
| if (pnode->value) |
| pnode->value = (char *)mxml_realloc(pnode->value, strlen(value)+1); |
| else if (value) |
| pnode->value = (char *)mxml_malloc(strlen(value)+1); |
| else |
| pnode->value = NULL; |
| if (value) |
| strcpy(pnode->value, value); |
| return TRUE; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| replace value os a subnode, like |
| <parent> |
| <child>value</child> |
| </parent> |
| if pnode=parent, and "name"="child", then "value" gets replaced |
| */ |
| int mxml_replace_subvalue(PMXML_NODE pnode, const char *name, const char *value) |
| { |
| int i; |
| for (i=0 ; i<pnode->n_children ; i++) |
| if (strcmp(pnode->child[i].name, name) == 0) |
| break; |
| if (i == pnode->n_children) |
| return FALSE; |
| return mxml_replace_node_value(&pnode->child[i], value); |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * change the name of an attribute, keep its value |
| */ |
| int mxml_replace_attribute_name(PMXML_NODE pnode, const char *old_name, const char *new_name) |
| { |
| int i; |
| for (i=0 ; i<pnode->n_attributes ; i++) |
| if (strcmp(pnode->attribute_name+i*MXML_NAME_LENGTH, old_name) == 0) |
| break; |
| if (i == pnode->n_attributes) |
| return FALSE; |
| strlcpy(pnode->attribute_name+i*MXML_NAME_LENGTH, new_name, MXML_NAME_LENGTH); |
| return TRUE; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * change the value of an attribute |
| */ |
| int mxml_replace_attribute_value(PMXML_NODE pnode, const char *attrib_name, const char *attrib_value) |
| { |
| int i; |
| for (i=0 ; i<pnode->n_attributes ; i++) |
| if (strcmp(pnode->attribute_name+i*MXML_NAME_LENGTH, attrib_name) == 0) |
| break; |
| if (i == pnode->n_attributes) |
| return FALSE; |
| pnode->attribute_value[i] = (char *)mxml_realloc(pnode->attribute_value[i], strlen(attrib_value)+1); |
| strcpy(pnode->attribute_value[i], attrib_value); |
| return TRUE; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * free memory of a node and remove it from the parent's child list |
| */ |
| int mxml_delete_node(PMXML_NODE pnode) |
| { |
| PMXML_NODE parent; |
| int i, j; |
| /* remove node from parent's list */ |
| parent = pnode->parent; |
| if (parent) { |
| for (i=0 ; i<parent->n_children ; i++) |
| if (&parent->child[i] == pnode) |
| break; |
| /* free allocated node memory recursively */ |
| mxml_free_tree(pnode); |
| if (i < parent->n_children) { |
| for (j=i ; j<parent->n_children-1 ; j++) |
| memcpy(&parent->child[j], &parent->child[j+1], sizeof(MXML_NODE)); |
| parent->n_children--; |
| if (parent->n_children) |
| parent->child = (PMXML_NODE)mxml_realloc(parent->child, sizeof(MXML_NODE)*(parent->n_children)); |
| else |
| mxml_free(parent->child); |
| } |
| } else |
| mxml_free_tree(pnode); |
| return TRUE; |
| } |
| /*------------------------------------------------------------------*/ |
| int mxml_delete_attribute(PMXML_NODE pnode, const char *attrib_name) |
| { |
| int i, j; |
| for (i=0 ; i<pnode->n_attributes ; i++) |
| if (strcmp(pnode->attribute_name+i*MXML_NAME_LENGTH, attrib_name) == 0) |
| break; |
| if (i == pnode->n_attributes) |
| return FALSE; |
| mxml_free(pnode->attribute_value[i]); |
| for (j=i ; j<pnode->n_attributes-1 ; j++) { |
| strcpy(pnode->attribute_name+j*MXML_NAME_LENGTH, pnode->attribute_name+(j+1)*MXML_NAME_LENGTH); |
| pnode->attribute_value[j] = pnode->attribute_value[j+1]; |
| } |
| if (pnode->n_attributes > 0) { |
| pnode->attribute_name = (char *)mxml_realloc(pnode->attribute_name, MXML_NAME_LENGTH*(pnode->n_attributes-1)); |
| pnode->attribute_value = (char **)mxml_realloc(pnode->attribute_value, sizeof(char *)*(pnode->n_attributes-1)); |
| } else { |
| mxml_free(pnode->attribute_name); |
| mxml_free(pnode->attribute_value); |
| } |
| return TRUE; |
| } |
| /*------------------------------------------------------------------*/ |
| #define HERE root, file_name, line_number, error, error_size, error_line |
| /** |
| * used inside mxml_parse_file for reporting errors |
| */ |
| PMXML_NODE read_error(PMXML_NODE root, const char *file_name, int line_number, char *error, int error_size, int *error_line, const char *format, ...) |
| { |
| char *msg, str[1000]; |
| va_list argptr; |
| if (file_name && file_name[0]) |
| sprintf(str, "XML read error in file \"%s\", line %d: ", file_name, line_number); |
| else |
| sprintf(str, "XML read error, line %d: ", line_number); |
| msg = (char *)mxml_malloc(error_size); |
| if (error) |
| strlcpy(error, str, error_size); |
| va_start(argptr, format); |
| vsprintf(str, (char *) format, argptr); |
| va_end(argptr); |
| if (error) |
| strlcat(error, str, error_size); |
| if (error_line) |
| *error_line = line_number; |
| mxml_free(msg); |
| mxml_free_tree(root); |
| return NULL; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * Parse a XML buffer and convert it into a tree of MXML_NODE's. |
| * Return NULL in case of an error, return error description. |
| * Optional file_name is used for error reporting if called from mxml_parse_file() |
| */ |
| PMXML_NODE mxml_parse_buffer(const char *buf, char *error, int error_size, int *error_line) |
| { |
| char node_name[256], attrib_name[256], attrib_value[1000], quote; |
| const char *p, *pv; |
| int i,j, line_number; |
| PMXML_NODE root, ptree, pnew; |
| int end_element; |
| size_t len; |
| char *file_name = NULL; /* dummy for 'HERE' */ |
| p = buf; |
| line_number = 1; |
| root = mxml_create_root_node(); |
| ptree = root; |
| /* parse file contents */ |
| do { |
| if (*p == '<') { |
| end_element = FALSE; |
| /* found new element */ |
| p++; |
| while (*p && isspace(*p)) { |
| if (*p == '\n') |
| line_number++; |
| p++; |
| } |
| if (!*p) |
| return read_error(HERE, "Unexpected end of file"); |
| if (strncmp(p, "!--", 3) == 0) { |
| /* found comment */ |
| pnew = mxml_add_special_node(ptree, COMMENT_NODE, "Comment", NULL); |
| pnew->line_number_start = line_number; |
| pv = p+3; |
| while (*pv == ' ') |
| pv++; |
| p += 3; |
| if (strstr(p, "-->") == NULL) |
| return read_error(HERE, "Unterminated comment"); |
| while (strncmp(p, "-->", 3) != 0) { |
| if (*p == '\n') |
| line_number++; |
| p++; |
| } |
| len = (size_t)p - (size_t)pv; |
| pnew->value = (char *)mxml_malloc(len+1); |
| memcpy(pnew->value, pv, len); |
| pnew->value[len] = 0; |
| pnew->line_number_end = line_number; |
| mxml_decode(pnew->value); |
| p += 3; |
| } else if (*p == '?') { |
| /* found ?...? element */ |
| pnew = mxml_add_special_node(ptree, PROCESSING_INSTRUCTION_NODE, "PI", NULL); |
| pnew->line_number_start = line_number; |
| pv = p+1; |
| p++; |
| if (strstr(p, "?>") == NULL) |
| return read_error(HERE, "Unterminated ?...? element"); |
| while (strncmp(p, "?>", 2) != 0) { |
| if (*p == '\n') |
| line_number++; |
| p++; |
| } |
| len = (size_t)p - (size_t)pv; |
| pnew->value = (char *)mxml_malloc(len+1); |
| memcpy(pnew->value, pv, len); |
| pnew->value[len] = 0; |
| pnew->line_number_end = line_number; |
| mxml_decode(pnew->value); |
| p += 2; |
| } else if (strncmp(p, "!DOCTYPE", 8) == 0 ) { |
| /* found !DOCTYPE element , skip it */ |
| p += 8; |
| if (strstr(p, ">") == NULL) |
| return read_error(HERE, "Unterminated !DOCTYPE element"); |
| j = 0; |
| while (*p && (*p != '>' || j > 0)) { |
| if (*p == '\n') |
| line_number++; |
| else if (*p == '<') |
| j++; |
| else if (*p == '>') |
| j--; |
| p++; |
| } |
| if (!*p) |
| return read_error(HERE, "Unexpected end of file"); |
| p++; |
| } else { |
| /* found normal element */ |
| if (*p == '/') { |
| end_element = TRUE; |
| p++; |
| while (*p && isspace((unsigned char)*p)) { |
| if (*p == '\n') |
| line_number++; |
| p++; |
| } |
| if (!*p) |
| return read_error(HERE, "Unexpected end of file"); |
| } |
| /* extract node name */ |
| i = 0; |
| node_name[i] = 0; |
| while (*p && !isspace((unsigned char)*p) && *p != '/' && *p != '>' && *p != '<') |
| node_name[i++] = *p++; |
| node_name[i] = 0; |
| if (!*p) |
| return read_error(HERE, "Unexpected end of file"); |
| if (*p == '<') |
| return read_error(HERE, "Unexpected \'<\' inside element \"%s\"", node_name); |
| mxml_decode(node_name); |
| if (end_element) { |
| if (!ptree) |
| return read_error(HERE, "Found unexpected </%s>", node_name); |
| /* close previously opened element */ |
| if (strcmp(ptree->name, node_name) != 0) |
| return read_error(HERE, "Found </%s>, expected </%s>", node_name, ptree->name); |
| ptree->line_number_end = line_number; |
| /* go up one level on the tree */ |
| ptree = ptree->parent; |
| } else { |
| if (ptree == NULL) |
| return read_error(HERE, "Unexpected second top level node"); |
| /* allocate new element structure in parent tree */ |
| pnew = mxml_add_node(ptree, node_name, NULL); |
| pnew->line_number_start = line_number; |
| pnew->line_number_end = line_number; |
| while (*p && isspace((unsigned char)*p)) { |
| if (*p == '\n') |
| line_number++; |
| p++; |
| } |
| if (!*p) |
| return read_error(HERE, "Unexpected end of file"); |
| while (*p != '>' && *p != '/') { |
| /* found attribute */ |
| pv = p; |
| while (*pv && !isspace((unsigned char)*pv) && *pv != '=' && *pv != '<' && *pv != '>') |
| pv++; |
| if (!*pv) |
| return read_error(HERE, "Unexpected end of file"); |
| if (*pv == '<' || *pv == '>') |
| return read_error(HERE, "Unexpected \'%c\' inside element \"%s\"", *pv, node_name); |
| /* extract attribute name */ |
| len = (size_t)pv - (size_t)p; |
| if (len > sizeof(attrib_name)-1) |
| len = sizeof(attrib_name)-1; |
| memcpy(attrib_name, p, len); |
| attrib_name[len] = 0; |
| mxml_decode(attrib_name); |
| p = pv; |
| while (*p && isspace((unsigned char)*p)) { |
| if (*p == '\n') |
| line_number++; |
| p++; |
| } |
| if (!*p) |
| return read_error(HERE, "Unexpected end of file"); |
| if (*p != '=') |
| return read_error(HERE, "Expect \"=\" here"); |
| p++; |
| while (*p && isspace((unsigned char)*p)) { |
| if (*p == '\n') |
| line_number++; |
| p++; |
| } |
| if (!*p) |
| return read_error(HERE, "Unexpected end of file"); |
| if (*p != '\"' && *p != '\'') |
| return read_error(HERE, "Expect \" or \' here"); |
| quote = *p; |
| p++; |
| /* extract attribute value */ |
| pv = p; |
| while (*pv && *pv != quote) |
| pv++; |
| if (!*pv) |
| return read_error(HERE, "Unexpected end of file"); |
| len = (size_t)pv - (size_t)p; |
| if (len > sizeof(attrib_value)-1) |
| len = sizeof(attrib_value)-1; |
| memcpy(attrib_value, p, len); |
| attrib_value[len] = 0; |
| mxml_decode(attrib_value); |
| /* add attribute to current node */ |
| mxml_add_attribute(pnew, attrib_name, attrib_value); |
| p = pv+1; |
| while (*p && isspace((unsigned char)*p)) { |
| if (*p == '\n') |
| line_number++; |
| p++; |
| } |
| if (!*p) |
| return read_error(HERE, "Unexpected end of file"); |
| } |
| if (*p == '/') { |
| /* found empty node, like <node/>, just skip closing bracket */ |
| p++; |
| while (*p && isspace((unsigned char)*p)) { |
| if (*p == '\n') |
| line_number++; |
| p++; |
| } |
| if (!*p) |
| return read_error(HERE, "Unexpected end of file"); |
| if (*p != '>') |
| return read_error(HERE, "Expected \">\" after \"/\""); |
| p++; |
| } |
| if (*p == '>') { |
| p++; |
| /* check if we have sub-element or value */ |
| pv = p; |
| while (*pv && isspace((unsigned char)*pv)) { |
| if (*pv == '\n') |
| line_number++; |
| pv++; |
| } |
| if (!*pv) |
| return read_error(HERE, "Unexpected end of file"); |
| if (*pv == '<' && *(pv+1) != '/') { |
| /* start new subtree */ |
| ptree = pnew; |
| p = pv; |
| } else { |
| /* extract value */ |
| while (*pv && *pv != '<') { |
| if (*pv == '\n') |
| line_number++; |
| pv++; |
| } |
| if (!*pv) |
| return read_error(HERE, "Unexpected end of file"); |
| len = (size_t)pv - (size_t)p; |
| pnew->value = (char *)mxml_malloc(len+1); |
| memcpy(pnew->value, p, len); |
| pnew->value[len] = 0; |
| mxml_decode(pnew->value); |
| p = pv; |
| ptree = pnew; |
| } |
| } |
| } |
| } |
| } |
| /* go to next element */ |
| while (*p && *p != '<') { |
| if (*p == '\n') |
| line_number++; |
| p++; |
| } |
| } while (*p); |
| return root; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * parse !ENTYTY entries of XML files and replace with references. |
| * Return 0 in case of no errors, return error description. |
| * Optional file_name is used for error reporting if called from mxml_parse_file() |
| */ |
| int mxml_parse_entity(char **buf, const char *file_name, char *error, int error_size, int *error_line) |
| { |
| char *p; |
| char *pv; |
| char delimiter; |
| int i, j, k, line_number, status; |
| char *replacement; |
| char entity_name[MXML_MAX_ENTITY][256]; |
| char entity_reference_name[MXML_MAX_ENTITY][256]; |
| char *entity_value[MXML_MAX_ENTITY]; |
| int entity_type[MXML_MAX_ENTITY]; /* internal or external */ |
| int entity_line_number[MXML_MAX_ENTITY]; |
| int nentity; |
| int fh, length, len; |
| char *buffer; |
| int ip; /* counter for entity value */ |
| char directoryname[FILENAME_MAX]; |
| char filename[FILENAME_MAX]; |
| int entity_value_length[MXML_MAX_ENTITY]; |
| int entity_name_length[MXML_MAX_ENTITY]; |
| PMXML_NODE root = mxml_create_root_node(); /* dummy for 'HERE' */ |
| for (ip = 0; ip < MXML_MAX_ENTITY; ip++) |
| entity_value[ip] = NULL; |
| line_number = 1; |
| nentity = -1; |
| status = 0; |
| if (!buf || !(*buf) || !strlen(*buf)) |
| return 0; |
| strcpy(directoryname, file_name); |
| mxml_dirname(directoryname); |
| /* copy string to temporary space */ |
| buffer = (char *) mxml_malloc(strlen(*buf) + 1); |
| if (buffer == NULL) { |
| read_error(HERE, "Cannot allocate memory."); |
| status = 1; |
| goto error; |
| } |
| strcpy(buffer, *buf); |
| p = strstr(buffer, "!DOCTYPE"); |
| if (p == NULL) { /* no entities */ |
| status = 0; |
| goto error; |
| } |
| pv = strstr(p, "["); |
| if (pv == NULL) { /* no entities */ |
| status = 1; |
| goto error; |
| } |
| p = pv + 1; |
| /* search !ENTITY */ |
| do { |
| if (*p == ']') |
| break; |
| if (*p == '<') { |
| /* found new entity */ |
| p++; |
| while (*p && isspace((unsigned char)*p)) { |
| if (*p == '\n') |
| line_number++; |
| p++; |
| } |
| if (!*p) { |
| read_error(HERE, "Unexpected end of file"); |
| status = 1; |
| goto error; |
| } |
| if (strncmp(p, "!--", 3) == 0) { |
| /* found comment */ |
| p += 3; |
| if (strstr(p, "-->") == NULL) { |
| read_error(HERE, "Unterminated comment"); |
| status = 1; |
| goto error; |
| } |
| while (strncmp(p, "-->", 3) != 0) { |
| if (*p == '\n') |
| line_number++; |
| p++; |
| } |
| p += 3; |
| } |
| else if (strncmp(p, "!ENTITY", 7) == 0) { |
| /* found entity */ |
| nentity++; |
| if (nentity >= MXML_MAX_ENTITY) { |
| read_error(HERE, "Too much entities"); |
| status = 1; |
| goto error; |
| } |
| entity_line_number[nentity] = line_number; |
| pv = p + 7; |
| while (*pv == ' ') |
| pv++; |
| /* extract entity name */ |
| p = pv; |
| while (*p && isspace((unsigned char)*p) && *p != '<' && *p != '>') { |
| if (*p == '\n') |
| line_number++; |
| p++; |
| } |
| if (!*p) { |
| read_error(HERE, "Unexpected end of file"); |
| status = 1; |
| goto error; |
| } |
| if (*p == '<' || *p == '>') { |
| read_error(HERE, "Unexpected \'%c\' inside !ENTITY", *p); |
| status = 1; |
| goto error; |
| } |
| pv = p; |
| while (*pv && !isspace((unsigned char)*pv) && *pv != '<' && *pv != '>') |
| pv++; |
| if (!*pv) { |
| read_error(HERE, "Unexpected end of file"); |
| status = 1; |
| goto error; |
| } |
| if (*pv == '<' || *pv == '>') { |
| read_error(HERE, "Unexpected \'%c\' inside entity \"%s\"", *pv, &entity_name[nentity][1]); |
| status = 1; |
| goto error; |
| } |
| entity_name[nentity][0] = '&'; |
| i = 1; |
| entity_name[nentity][i] = 0; |
| while (*p && !isspace((unsigned char)*p) && *p != '/' && *p != '>' && *p != '<' && i < 253) |
| entity_name[nentity][i++] = *p++; |
| entity_name[nentity][i++] = ';'; |
| entity_name[nentity][i] = 0; |
| if (!*p) { |
| read_error(HERE, "Unexpected end of file"); |
| status = 1; |
| goto error; |
| } |
| if (*p == '<') { |
| read_error(HERE, "Unexpected \'<\' inside entity \"%s\"", &entity_name[nentity][1]); |
| status = 1; |
| goto error; |
| } |
| /* extract replacement or SYSTEM */ |
| while (*p && isspace((unsigned char)*p)) { |
| if (*p == '\n') |
| line_number++; |
| p++; |
| } |
| if (!*p) { |
| read_error(HERE, "Unexpected end of file"); |
| status = 1; |
| goto error; |
| } |
| if (*p == '>') { |
| read_error(HERE, "Unexpected \'>\' inside entity \"%s\"", &entity_name[nentity][1]); |
| status = 1; |
| goto error; |
| } |
| /* check if SYSTEM */ |
| if (strncmp(p, "SYSTEM", 6) == 0) { |
| entity_type[nentity] = EXTERNAL_ENTITY; |
| p += 6; |
| } else { |
| entity_type[nentity] = INTERNAL_ENTITY; |
| } |
| /* extract replacement */ |
| while (*p && isspace((unsigned char)*p)) { |
| if (*p == '\n') |
| line_number++; |
| p++; |
| } |
| if (!*p) { |
| read_error(HERE, "Unexpected end of file"); |
| status = 1; |
| goto error; |
| } |
| if (*p == '>') { |
| read_error(HERE, "Unexpected \'>\' inside entity \"%s\"", &entity_name[nentity][1]); |
| status = 1; |
| goto error; |
| } |
| if (*p != '\"' && *p != '\'') { |
| read_error(HERE, "Replacement was not found for entity \"%s\"", &entity_name[nentity][1]); |
| status = 1; |
| goto error; |
| } |
| delimiter = *p; |
| p++; |
| if (!*p) { |
| read_error(HERE, "Unexpected end of file"); |
| status = 1; |
| goto error; |
| } |
| pv = p; |
| while (*pv && *pv != delimiter) |
| pv++; |
| if (!*pv) { |
| read_error(HERE, "Unexpected end of file"); |
| status = 1; |
| goto error; |
| } |
| if (*pv == '<') { |
| read_error(HERE, "Unexpected \'%c\' inside entity \"%s\"", *pv, &entity_name[nentity][1]); |
| status = 1; |
| goto error; |
| } |
| len = (int)((size_t) pv - (size_t) p); |
| replacement = (char *) mxml_malloc(len + 1); |
| if (replacement == NULL) { |
| read_error(HERE, "Cannot allocate memory."); |
| status = 1; |
| goto error; |
| } |
| memcpy(replacement, p, len); |
| replacement[len] = 0; |
| mxml_decode(replacement); |
| if (entity_type[nentity] == EXTERNAL_ENTITY) { |
| strcpy(entity_reference_name[nentity], replacement); |
| } else { |
| entity_value[nentity] = (char *) mxml_malloc(strlen(replacement)); |
| if (entity_value[nentity] == NULL) { |
| read_error(HERE, "Cannot allocate memory."); |
| status = 1; |
| goto error; |
| } |
| strcpy(entity_value[nentity], replacement); |
| } |
| mxml_free(replacement); |
| p = pv; |
| while (*p && isspace((unsigned char)*p)) { |
| if (*p == '\n') |
| line_number++; |
| p++; |
| } |
| if (!*p) { |
| read_error(HERE, "Unexpected end of file"); |
| status = 1; |
| goto error; |
| } |
| } |
| } |
| /* go to next element */ |
| while (*p && *p != '<') { |
| if (*p == '\n') |
| line_number++; |
| p++; |
| } |
| } while (*p); |
| nentity++; |
| /* read external file */ |
| for (i = 0; i < nentity; i++) { |
| if (entity_type[i] == EXTERNAL_ENTITY) { |
| if ( entity_reference_name[i][0] == DIR_SEPARATOR ) /* absolute path */ |
| strcpy(filename, entity_reference_name[i]); |
| else /* relative path */ |
| sprintf(filename, "%s%c%s", directoryname, DIR_SEPARATOR, entity_reference_name[i]); |
| fh = open(filename, O_RDONLY | O_TEXT, 0644); |
| if (fh == -1) { |
| line_number = entity_line_number[i]; |
| read_error(HERE, "%s is missing", entity_reference_name[i]); |
| status = 1; |
| goto error; |
| } else { |
| length = (int)lseek(fh, 0, SEEK_END); |
| lseek(fh, 0, SEEK_SET); |
| if (length == 0) { |
| entity_value[i] = (char *) mxml_malloc(1); |
| if (entity_value[i] == NULL) { |
| read_error(HERE, "Cannot allocate memory."); |
| close(fh); |
| status = 1; |
| goto error; |
| } |
| entity_value[i][0] = 0; |
| } else { |
| entity_value[i] = (char *) mxml_malloc(length); |
| if (entity_value[i] == NULL) { |
| read_error(HERE, "Cannot allocate memory."); |
| close(fh); |
| status = 1; |
| goto error; |
| } |
| /* read complete file at once */ |
| length = (int)read(fh, entity_value[i], length); |
| entity_value[i][length - 1] = 0; |
| close(fh); |
| /* recursive parse */ |
| if (mxml_parse_entity(&entity_value[i], filename, error, error_size, error_line) != 0) { |
| status = 1; |
| goto error; |
| } |
| } |
| } |
| } |
| } |
| /* count length of output string */ |
| length = (int)strlen(buffer); |
| for (i = 0; i < nentity; i++) { |
| p = buffer; |
| entity_value_length[i] = (int)strlen(entity_value[i]); |
| entity_name_length[i] = (int)strlen(entity_name[i]); |
| while (1) { |
| pv = strstr(p, entity_name[i]); |
| if (pv) { |
| length += entity_value_length[i] - entity_name_length[i]; |
| p = pv + 1; |
| } else { |
| break; |
| } |
| } |
| } |
| /* re-allocate memory */ |
| *buf = (char *) mxml_realloc(*buf, length + 1); |
| if (*buf == NULL) { |
| read_error(HERE, "Cannot allocate memory."); |
| status = 1; |
| goto error; |
| } |
| /* replace entities */ |
| p = buffer; |
| pv = *buf; |
| do { |
| if (*p == '&') { |
| /* found entity */ |
| for (j = 0; j < nentity; j++) { |
| if (strncmp(p, entity_name[j], entity_name_length[j]) == 0) { |
| for (k = 0; k < (int) entity_value_length[j]; k++) |
| *pv++ = entity_value[j][k]; |
| p += entity_name_length[j]; |
| break; |
| } |
| } |
| } |
| *pv++ = *p++; |
| } while (*p); |
| *pv = 0; |
| error: |
| if (buffer != NULL) |
| mxml_free(buffer); |
| for (ip = 0; ip < MXML_MAX_ENTITY; ip++) |
| if (entity_value[ip] != NULL) |
| mxml_free(entity_value[ip]); |
| return status; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * parse a XML file and convert it into a tree of MXML_NODE's. |
| * Return NULL in case of an error, return error description |
| */ |
| PMXML_NODE mxml_parse_file(const char *file_name, char *error, int error_size, int *error_line) |
| { |
| char *buf, line[1000]; |
| int fh, length; |
| PMXML_NODE root; |
| if (error) |
| error[0] = 0; |
| fh = open(file_name, O_RDONLY | O_TEXT, 0644); |
| if (fh == -1) { |
| sprintf(line, "Unable to open file \"%s\": ", file_name); |
| strlcat(line, strerror(errno), sizeof(line)); |
| strlcpy(error, line, error_size); |
| return NULL; |
| } |
| length = (int)lseek(fh, 0, SEEK_END); |
| lseek(fh, 0, SEEK_SET); |
| buf = (char *)mxml_malloc(length+1); |
| if (buf == NULL) { |
| close(fh); |
| sprintf(line, "Cannot allocate buffer: "); |
| strlcat(line, strerror(errno), sizeof(line)); |
| strlcpy(error, line, error_size); |
| return NULL; |
| } |
| /* read complete file at once */ |
| length = (int)read(fh, buf, length); |
| buf[length] = 0; |
| close(fh); |
| if (mxml_parse_entity(&buf, file_name, error, error_size, error_line) != 0) { |
| mxml_free(buf); |
| return NULL; |
| } |
| root = mxml_parse_buffer(buf, error, error_size, error_line); |
| mxml_free(buf); |
| return root; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * write complete subtree recursively into file opened with mxml_open_document() |
| */ |
| int mxml_write_subtree(MXML_WRITER *writer, PMXML_NODE tree, int indent) |
| { |
| int i; |
| mxml_start_element1(writer, tree->name, indent); |
| for (i=0 ; i<tree->n_attributes ; i++) |
| if (!mxml_write_attribute(writer, tree->attribute_name+i*MXML_NAME_LENGTH, tree->attribute_value[i])) |
| return FALSE; |
| if (tree->value) |
| if (!mxml_write_value(writer, tree->value)) |
| return FALSE; |
| for (i=0 ; i<tree->n_children ; i++) |
| if (!mxml_write_subtree(writer, &tree->child[i], (tree->value == NULL) || i > 0)) |
| return FALSE; |
| return mxml_end_element(writer); |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * write a complete XML tree to a file |
| */ |
| int mxml_write_tree(const char *file_name, PMXML_NODE tree) |
| { |
| MXML_WRITER *writer; |
| int i; |
| assert(tree); |
| writer = mxml_open_file(file_name); |
| if (!writer) |
| return FALSE; |
| for (i=0 ; i<tree->n_children ; i++) |
| if (tree->child[i].node_type == ELEMENT_NODE) /* skip PI and comments */ |
| if (!mxml_write_subtree(writer, &tree->child[i], TRUE)) |
| return FALSE; |
| if (!mxml_close_file(writer)) |
| return FALSE; |
| return TRUE; |
| } |
| /*------------------------------------------------------------------*/ |
| PMXML_NODE mxml_clone_tree(PMXML_NODE tree) |
| { |
| PMXML_NODE clone; |
| int i; |
| clone = (PMXML_NODE)calloc(sizeof(MXML_NODE), 1); |
| /* copy name, node_type, n_attributes and n_children */ |
| memcpy(clone, tree, sizeof(MXML_NODE)); |
| clone->value = NULL; |
| mxml_replace_node_value(clone, tree->value); |
| clone->attribute_name = NULL; |
| clone->attribute_value = NULL; |
| for (i=0 ; i<tree->n_attributes ; i++) |
| mxml_add_attribute(clone, tree->attribute_name+i*MXML_NAME_LENGTH, tree->attribute_value[i]); |
| clone->child = NULL; |
| clone->n_children = 0; |
| for (i=0 ; i<tree->n_children ; i++) |
| mxml_add_tree(clone, mxml_clone_tree(mxml_subnode(tree, i))); |
| return clone; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * print XML tree for debugging |
| */ |
| void mxml_debug_tree(PMXML_NODE tree, int level) |
| { |
| int i, j; |
| for (i=0 ; i<level ; i++) |
| printf(" "); |
| printf("Name: %s\n", tree->name); |
| for (i=0 ; i<level ; i++) |
| printf(" "); |
| printf("Valu: %s\n", tree->value); |
| for (i=0 ; i<level ; i++) |
| printf(" "); |
| printf("Type: %d\n", tree->node_type); |
| for (i=0 ; i<level ; i++) |
| printf(" "); |
| printf("Lin1: %d\n", tree->line_number_start); |
| for (i=0 ; i<level ; i++) |
| printf(" "); |
| printf("Lin2: %d\n", tree->line_number_end); |
| for (j=0 ; j<tree->n_attributes ; j++) { |
| for (i=0 ; i<level ; i++) |
| printf(" "); |
| printf("%s: %s\n", tree->attribute_name+j*MXML_NAME_LENGTH, |
| tree->attribute_value[j]); |
| } |
| for (i=0 ; i<level ; i++) |
| printf(" "); |
| printf("Addr: %08zX\n", (size_t)tree); |
| for (i=0 ; i<level ; i++) |
| printf(" "); |
| printf("Prnt: %08zX\n", (size_t)tree->parent); |
| for (i=0 ; i<level ; i++) |
| printf(" "); |
| printf("NCld: %d\n", tree->n_children); |
| for (i=0 ; i<tree->n_children ; i++) |
| mxml_debug_tree(tree->child+i, level+1); |
| if (level == 0) |
| printf("\n"); |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * free memory of XML tree, must be called after any |
| * mxml_create_root_node() or mxml_parse_file() |
| */ |
| void mxml_free_tree(PMXML_NODE tree) |
| { |
| int i; |
| /* first free children recursively */ |
| for (i=0 ; i<tree->n_children ; i++) |
| mxml_free_tree(&tree->child[i]); |
| if (tree->n_children) |
| mxml_free(tree->child); |
| /* now free dynamic data */ |
| for (i=0 ; i<tree->n_attributes ; i++) |
| mxml_free(tree->attribute_value[i]); |
| if (tree->n_attributes) { |
| mxml_free(tree->attribute_name); |
| mxml_free(tree->attribute_value); |
| } |
| if (tree->value) |
| mxml_free(tree->value); |
| /* if we are the root node, free it */ |
| if (tree->parent == NULL) |
| mxml_free(tree); |
| } |
| /*------------------------------------------------------------------*/ |
| /* |
| void mxml_test() |
| { |
| char err[256]; |
| PMXML_NODE tree, tree2, node; |
| tree = mxml_parse_file("c:\\tmp\\test.xml", err, sizeof(err)); |
| tree2 = mxml_clone_tree(tree); |
| printf("Orig:\n"); |
| mxml_debug_tree(tree, 0); |
| printf("\nClone:\n"); |
| mxml_debug_tree(tree2, 0); |
| printf("\nCombined:\n"); |
| node = mxml_find_node(tree2, "cddb"); |
| mxml_add_tree(tree, node); |
| mxml_debug_tree(tree, 0); |
| mxml_free_tree(tree); |
| } |
| */ |
| /*------------------------------------------------------------------*/ |
| /** |
| mxml_basename deletes any prefix ending with the last slash '/' character |
| present in path. mxml_dirname deletes the filename portion, beginning with |
| the last slash '/' character to the end of path. Followings are examples |
| from these functions |
| path dirname basename |
| "/" "/" "" |
| "." "." "." |
| "" "" "" |
| "/test.txt" "/" "test.txt" |
| "path/to/test.txt" "path/to" "test.txt" |
| "test.txt "." "test.txt" |
| Under Windows, '\\' and ':' are recognized ad separator too. |
| */ |
| void mxml_basename(char *path) |
| { |
| char str[FILENAME_MAX]; |
| char *p; |
| char *name; |
| if (path) { |
| strcpy(str, path); |
| p = str; |
| name = str; |
| while (1) { |
| if (*p == 0) |
| break; |
| if (*p == '/' |
| #ifdef _MSC_VER |
| || *p == ':' || *p == '\\' |
| #endif |
| ) |
| name = p + 1; |
| p++; |
| } |
| strcpy(path, name); |
| } |
| return; |
| } |
| void mxml_dirname(char *path) |
| { |
| char *p; |
| #ifdef _MSC_VER |
| char *pv; |
| #endif |
| if (!path || strlen(path) == 0) |
| return; |
| p = strrchr(path, '/'); |
| #ifdef _MSC_VER |
| pv = strrchr(path, ':'); |
| if (pv > p) |
| p = pv; |
| pv = strrchr(path, '\\'); |
| if (pv > p) |
| p = pv; |
| #endif |
| if (p == 0) /* current directory */ |
| strcpy(path, "."); |
| else if (p == path) /* root directory */ |
| sprintf(path, "%c", *p); |
| else |
| *p = 0; |
| return; |
| } |
| /*------------------------------------------------------------------*/ |
| /** |
| * Retieve node at a certain line number |
| */ |
| PMXML_NODE mxml_get_node_at_line(PMXML_NODE tree, int line_number) |
| { |
| int i; |
| PMXML_NODE pn; |
| if (tree->line_number_start == line_number) |
| return tree; |
| for (i=0 ; i<tree->n_children ; i++) { |
| pn = mxml_get_node_at_line(&tree->child[i], line_number); |
| if (pn) |
| return pn; |
| } |
| return NULL; |
| } |
| /cvi/instr/drsctrl/mxml.h |
|---|
| 0,0 → 1,156 |
| /********************************************************************\ |
| Name: mxml.h |
| Created by: Stefan Ritt |
| Copyright 2000 + Stefan Ritt |
| Contents: Header file for mxml.c |
| This file is part of MIDAS XML Library. |
| MIDAS XML Library is free software: you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| MIDAS XML Library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| You should have received a copy of the GNU General Public License |
| along with MIDAS XML Library. If not, see <http://www.gnu.org/licenses/>. |
| \********************************************************************/ |
| /*------------------------------------------------------------------*/ |
| #ifndef _MXML_H_ |
| #define _MXML_H_ |
| #define MXML_NAME_LENGTH 64 |
| #define ELEMENT_NODE 1 |
| #define TEXT_NODE 2 |
| #define PROCESSING_INSTRUCTION_NODE 3 |
| #define COMMENT_NODE 4 |
| #define DOCUMENT_NODE 5 |
| #define INTERNAL_ENTITY 0 |
| #define EXTERNAL_ENTITY 1 |
| #define MXML_MAX_ENTITY 500 |
| #define MXML_MAX_CONDITION 10 |
| #ifdef _MSC_VER |
| #define DIR_SEPARATOR '\\' |
| #else |
| #define DIR_SEPARATOR '/' |
| #endif |
| typedef struct { |
| int fh; |
| char *buffer; |
| int buffer_size; |
| int buffer_len; |
| int level; |
| int element_is_open; |
| int data_was_written; |
| char **stack; |
| int translate; |
| } MXML_WRITER; |
| typedef struct mxml_struct *PMXML_NODE; |
| typedef struct mxml_struct { |
| char name[MXML_NAME_LENGTH]; // name of element <[name]>[value]</[name]> |
| int node_type; // type of node XXX_NODE |
| char *value; // value of element |
| int n_attributes; // list of attributes |
| char *attribute_name; |
| char **attribute_value; |
| int line_number_start; // first line number in XML file, starting from 1 |
| int line_number_end; // last line number in XML file, starting from 1 |
| PMXML_NODE parent; // pointer to parent element |
| int n_children; // list of children |
| PMXML_NODE child; |
| } MXML_NODE; |
| /*------------------------------------------------------------------*/ |
| /* make functions callable from a C++ program */ |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| #ifndef EXPRT |
| #if defined(EXPORT_DLL) |
| #define EXPRT __declspec(dllexport) |
| #else |
| #define EXPRT |
| #endif |
| #endif |
| void mxml_suppress_date(int suppress); |
| MXML_WRITER *mxml_open_file(const char *file_name); |
| MXML_WRITER *mxml_open_buffer(void); |
| int mxml_set_translate(MXML_WRITER *writer, int flag); |
| int mxml_start_element(MXML_WRITER *writer, const char *name); |
| int mxml_start_element_noindent(MXML_WRITER *writer, const char *name); |
| int mxml_end_element(MXML_WRITER *writer); |
| int mxml_write_comment(MXML_WRITER *writer, const char *string); |
| int mxml_write_element(MXML_WRITER *writer, const char *name, const char *value); |
| int mxml_write_attribute(MXML_WRITER *writer, const char *name, const char *value); |
| int mxml_write_value(MXML_WRITER *writer, const char *value); |
| int mxml_write_empty_line(MXML_WRITER *writer); |
| char *mxml_close_buffer(MXML_WRITER *writer); |
| int mxml_close_file(MXML_WRITER *writer); |
| int mxml_get_number_of_children(PMXML_NODE pnode); |
| PMXML_NODE mxml_get_parent(PMXML_NODE pnode); |
| PMXML_NODE mxml_subnode(PMXML_NODE pnode, int idx); |
| PMXML_NODE mxml_find_node(PMXML_NODE tree, const char *xml_path); |
| int mxml_find_nodes(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist); |
| char *mxml_get_name(PMXML_NODE pnode); |
| char *mxml_get_value(PMXML_NODE pnode); |
| int mxml_get_line_number_start(PMXML_NODE pnode); |
| int mxml_get_line_number_end(PMXML_NODE pnode); |
| PMXML_NODE mxml_get_node_at_line(PMXML_NODE tree, int linenumber); |
| char *mxml_get_attribute(PMXML_NODE pnode, const char *name); |
| int mxml_add_attribute(PMXML_NODE pnode, const char *attrib_name, const char *attrib_value); |
| PMXML_NODE mxml_add_special_node(PMXML_NODE parent, int node_type, const char *node_name, const char *value); |
| PMXML_NODE mxml_add_special_node_at(PMXML_NODE parent, int node_type, const char *node_name, const char *value, int idx); |
| PMXML_NODE mxml_add_node(PMXML_NODE parent, const char *node_name, const char *value); |
| PMXML_NODE mxml_add_node_at(PMXML_NODE parent, const char *node_name, const char *value, int idx); |
| PMXML_NODE mxml_clone_tree(PMXML_NODE tree); |
| int mxml_add_tree(PMXML_NODE parent, PMXML_NODE tree); |
| int mxml_add_tree_at(PMXML_NODE parent, PMXML_NODE tree, int idx); |
| int mxml_replace_node_name(PMXML_NODE pnode, const char *new_name); |
| int mxml_replace_node_value(PMXML_NODE pnode, const char *value); |
| int mxml_replace_subvalue(PMXML_NODE pnode, const char *name, const char *value); |
| int mxml_replace_attribute_name(PMXML_NODE pnode, const char *old_name, const char *new_name); |
| int mxml_replace_attribute_value(PMXML_NODE pnode, const char *attrib_name, const char *attrib_value); |
| int mxml_delete_node(PMXML_NODE pnode); |
| int mxml_delete_attribute(PMXML_NODE, const char *attrib_name); |
| PMXML_NODE mxml_create_root_node(void); |
| PMXML_NODE mxml_parse_file(const char *file_name, char *error, int error_size, int *error_line); |
| PMXML_NODE mxml_parse_buffer(const char *buffer, char *error, int error_size, int *error_line); |
| int mxml_parse_entity(char **buf, const char* file_name, char *error, int error_size, int *error_line); |
| int mxml_write_tree(const char *file_name, PMXML_NODE tree); |
| void mxml_debug_tree(PMXML_NODE tree, int level); |
| void mxml_free_tree(PMXML_NODE tree); |
| void mxml_dirname(char* path); |
| void mxml_basename(char *path); |
| #ifdef __cplusplus |
| } |
| #endif |
| #endif /* _MXML_H_ */ |
| /*------------------------------------------------------------------*/ |
| /cvi/instr/drsctrl/mxml.obj |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |
| /cvi/instr/drsctrl/rb.cpp |
|---|
| 0,0 → 1,387 |
| /********************************************************************\ |
| Name: rb.c |
| Created by: Stefan Ritt |
| $Id: rb.cpp 21437 2014-07-30 14:13:29Z ritt $ |
| \********************************************************************/ |
| #include <stdio.h> |
| #ifdef OS_DARWIN |
| #include <sys/malloc.h> |
| #else |
| #include <malloc.h> |
| #endif |
| #include <string.h> |
| #include <assert.h> |
| #include "rb.h" |
| /********************************************************************\ |
| * * |
| * Ring buffer functions * |
| * * |
| * Provide an inter-thread buffer scheme for handling front-end * |
| * events. This code allows concurrent data acquisition, calibration * |
| * and network transfer on a multi-CPU machine. One thread reads * |
| * out the data, passes it vis the ring buffer functions * |
| * to another thread running on the other CPU, which can then * |
| * calibrate and/or send the data over the network. * |
| * * |
| \********************************************************************/ |
| typedef struct { |
| unsigned char *buffer; |
| unsigned int size; |
| unsigned int max_event_size; |
| unsigned char *rp; |
| unsigned char *wp; |
| unsigned char *ep; |
| } RING_BUFFER; |
| #define MAX_RING_BUFFER 100 |
| RING_BUFFER rb[MAX_RING_BUFFER]; |
| volatile int _rb_nonblocking = 0; |
| extern void ss_sleep(int ms); |
| int rb_set_nonblocking() |
| /********************************************************************\ |
| Routine: rb_set_nonblocking |
| Purpose: Set all rb_get_xx to nonblocking. Needed in multi-thread |
| environments for stopping all theads without deadlock |
| Input: |
| NONE |
| Output: |
| NONE |
| Function value: |
| RB_SUCCESS Successful completion |
| \********************************************************************/ |
| { |
| _rb_nonblocking = 1; |
| return RB_SUCCESS; |
| } |
| int rb_create(int size, int max_event_size, int *handle) |
| /********************************************************************\ |
| Routine: rb_create |
| Purpose: Create a ring buffer with a given size |
| Input: |
| int size Size of ring buffer, must be larger than |
| 2*max_event_size |
| int max_event_size Maximum event size to be placed into |
| ring buffer |
| Output: |
| int *handle Handle to ring buffer |
| Function value: |
| DB_SUCCESS Successful completion |
| DB_NO_MEMORY Maximum number of ring buffers exceeded |
| DB_INVALID_PARAM Invalid event size specified |
| \********************************************************************/ |
| { |
| int i; |
| for (i = 0; i < MAX_RING_BUFFER; i++) |
| if (rb[i].buffer == NULL) |
| break; |
| if (i == MAX_RING_BUFFER) |
| return RB_NO_MEMORY; |
| if (size < max_event_size * 2) |
| return RB_INVALID_PARAM; |
| memset(&rb[i], 0, sizeof(RING_BUFFER)); |
| rb[i].buffer = (unsigned char *) malloc(size); |
| assert(rb[i].buffer); |
| rb[i].size = size; |
| rb[i].max_event_size = max_event_size; |
| rb[i].rp = rb[i].buffer; |
| rb[i].wp = rb[i].buffer; |
| rb[i].ep = rb[i].buffer; |
| *handle = i + 1; |
| return RB_SUCCESS; |
| } |
| int rb_delete(int handle) |
| /********************************************************************\ |
| Routine: rb_delete |
| Purpose: Delete a ring buffer |
| Input: |
| none |
| Output: |
| int handle Handle to ring buffer |
| Function value: |
| DB_SUCCESS Successful completion |
| \********************************************************************/ |
| { |
| if (handle < 0 || handle >= MAX_RING_BUFFER || rb[handle - 1].buffer == NULL) |
| return RB_INVALID_HANDLE; |
| free(rb[handle - 1].buffer); |
| memset(&rb[handle - 1], 0, sizeof(RING_BUFFER)); |
| return RB_SUCCESS; |
| } |
| int rb_get_wp(int handle, void **p, int millisec) |
| /********************************************************************\ |
| Routine: rb_get_wp |
| Purpose: Retrieve write pointer where new data can be written |
| Input: |
| int handle Ring buffer handle |
| int millisec Optional timeout in milliseconds if |
| buffer is full. Zero to not wait at |
| all (non-blocking) |
| Output: |
| char **p Write pointer |
| Function value: |
| DB_SUCCESS Successful completion |
| \********************************************************************/ |
| { |
| int h, i; |
| unsigned char *rp; |
| if (handle < 1 || handle > MAX_RING_BUFFER || rb[handle - 1].buffer == NULL) |
| return RB_INVALID_HANDLE; |
| h = handle - 1; |
| for (i = 0; i <= millisec / 10; i++) { |
| rp = rb[h].rp; // keep local copy, rb[h].rp might be changed by other thread |
| /* check if enough size for wp >= rp without wrap-around */ |
| if (rb[h].wp >= rp |
| && rb[h].wp + rb[h].max_event_size <= rb[h].buffer + rb[h].size - rb[h].max_event_size) { |
| *p = rb[h].wp; |
| return RB_SUCCESS; |
| } |
| /* check if enough size for wp >= rp with wrap-around */ |
| if (rb[h].wp >= rp && rb[h].wp + rb[h].max_event_size > rb[h].buffer + rb[h].size - rb[h].max_event_size && rb[h].rp > rb[h].buffer) { // next increment of wp wraps around, so need space at beginning |
| *p = rb[h].wp; |
| return RB_SUCCESS; |
| } |
| /* check if enough size for wp < rp */ |
| if (rb[h].wp < rp && rb[h].wp + rb[h].max_event_size < rp) { |
| *p = rb[h].wp; |
| return RB_SUCCESS; |
| } |
| if (millisec == 0) |
| return RB_TIMEOUT; |
| if (_rb_nonblocking) |
| return RB_TIMEOUT; |
| /* wait one time slice */ |
| ss_sleep(10); |
| } |
| return RB_TIMEOUT; |
| } |
| int rb_increment_wp(int handle, int size) |
| /********************************************************************\ |
| Routine: rb_increment_wp |
| Purpose: Increment current write pointer, making the data at |
| the write pointer available to the receiving thread |
| Input: |
| int handle Ring buffer handle |
| int size Number of bytes placed at the WP |
| Output: |
| NONE |
| Function value: |
| RB_SUCCESS Successful completion |
| RB_INVALID_PARAM Event size too large or invalid handle |
| \********************************************************************/ |
| { |
| int h; |
| unsigned char *new_wp; |
| if (handle < 1 || handle > MAX_RING_BUFFER || rb[handle - 1].buffer == NULL) |
| return RB_INVALID_HANDLE; |
| h = handle - 1; |
| if ((unsigned int) size > rb[h].max_event_size) |
| return RB_INVALID_PARAM; |
| new_wp = rb[h].wp + size; |
| /* wrap around wp if not enough space */ |
| if (new_wp > rb[h].buffer + rb[h].size - rb[h].max_event_size) { |
| rb[h].ep = new_wp; |
| new_wp = rb[h].buffer; |
| assert(rb[h].rp != rb[h].buffer); |
| } |
| rb[h].wp = new_wp; |
| return RB_SUCCESS; |
| } |
| int rb_get_rp(int handle, void **p, int millisec) |
| /********************************************************************\ |
| Routine: rb_get_rp |
| Purpose: Obtain the current read pointer at which new data is |
| available with optional timeout |
| Input: |
| int handle Ring buffer handle |
| int millisec Optional timeout in milliseconds if |
| buffer is full. Zero to not wait at |
| all (non-blocking) |
| Output: |
| char **p Address of pointer pointing to newly |
| available data. If p == NULL, only |
| return status. |
| Function value: |
| RB_SUCCESS Successful completion |
| \********************************************************************/ |
| { |
| int i, h; |
| if (handle < 1 || handle > MAX_RING_BUFFER || rb[handle - 1].buffer == NULL) |
| return RB_INVALID_HANDLE; |
| h = handle - 1; |
| for (i = 0; i <= millisec / 10; i++) { |
| if (rb[h].wp != rb[h].rp) { |
| if (p != NULL) |
| *p = rb[handle - 1].rp; |
| return RB_SUCCESS; |
| } |
| if (millisec == 0) |
| return RB_TIMEOUT; |
| if (_rb_nonblocking) |
| return RB_TIMEOUT; |
| /* wait one time slice */ |
| ss_sleep(10); |
| } |
| return RB_TIMEOUT; |
| } |
| int rb_increment_rp(int handle, int size) |
| /********************************************************************\ |
| Routine: rb_increment_rp |
| Purpose: Increment current read pointer, freeing up space for |
| the writing thread. |
| Input: |
| int handle Ring buffer handle |
| int size Number of bytes to free up at current |
| read pointer |
| Output: |
| NONE |
| Function value: |
| RB_SUCCESS Successful completion |
| RB_INVALID_PARAM Event size too large or invalid handle |
| \********************************************************************/ |
| { |
| int h; |
| unsigned char *new_rp; |
| if (handle < 1 || handle > MAX_RING_BUFFER || rb[handle - 1].buffer == NULL) |
| return RB_INVALID_HANDLE; |
| h = handle - 1; |
| if ((unsigned int) size > rb[h].max_event_size) |
| return RB_INVALID_PARAM; |
| new_rp = rb[h].rp + size; |
| /* wrap around if not enough space left */ |
| if (new_rp + rb[h].max_event_size > rb[h].buffer + rb[h].size) |
| new_rp = rb[h].buffer; |
| rb[handle - 1].rp = new_rp; |
| return RB_SUCCESS; |
| } |
| int rb_get_buffer_level(int handle, int *n_bytes) |
| /********************************************************************\ |
| Routine: rb_get_buffer_level |
| Purpose: Return number of bytes in a ring buffer |
| Input: |
| int handle Handle of the buffer to get the info |
| Output: |
| int *n_bytes Number of bytes in buffer |
| Function value: |
| RB_SUCCESS Successful completion |
| RB_INVALID_HANDLE Buffer handle is invalid |
| \********************************************************************/ |
| { |
| int h; |
| if (handle < 1 || handle > MAX_RING_BUFFER || rb[handle - 1].buffer == NULL) |
| return RB_INVALID_HANDLE; |
| h = handle - 1; |
| if (rb[h].wp >= rb[h].rp) |
| *n_bytes = rb[h].wp - rb[h].rp; |
| else |
| *n_bytes = rb[h].ep - rb[h].rp + rb[h].wp - rb[h].buffer; |
| return RB_SUCCESS; |
| } |
| /cvi/instr/drsctrl/rb.h |
|---|
| 0,0 → 1,28 |
| /********************************************************************\ |
| Name: rb.h |
| Created by: Stefan Ritt |
| Contents: Function declarations and constants for ring buffer |
| routines |
| $Id: rb.h 17217 2011-02-25 15:31:29Z ritt $ |
| \********************************************************************/ |
| #define RB_SUCCESS 1 |
| #define RB_NO_MEMORY 2 |
| #define RB_INVALID_PARAM 3 |
| #define RB_INVALID_HANDLE 4 |
| #define RB_TIMEOUT 5 |
| #define POINTER_T unsigned int |
| int rb_set_nonblocking(); |
| int rb_create(int size, int max_event_size, int *ring_buffer_handle); |
| int rb_delete(int ring_buffer_handle); |
| int rb_get_wp(int handle, void **p, int millisec); |
| int rb_increment_wp(int handle, int size); |
| int rb_get_rp(int handle, void **p, int millisec); |
| int rb_increment_rp(int handle, int size); |
| int rb_get_buffer_level(int handle, int * n_bytes); |
| /cvi/instr/drsctrl/read_binary.cpp |
|---|
| 0,0 → 1,250 |
| /* |
| Name: read_binary.cpp |
| Created by: Stefan Ritt <stefan.ritt@psi.ch> |
| Date: July 30th, 2014 |
| Purpose: Example file to read binary data saved by DRSOsc. |
| Compile and run it with: |
| gcc -o read_binary read_binary.cpp |
| ./read_binary <filename> |
| This program assumes that a pulse from a signal generator is split |
| and fed into channels #1 and #2. It then calculates the time difference |
| between these two pulses to show the performance of the DRS board |
| for time measurements. |
| $Id: read_binary.cpp 22321 2016-08-25 12:26:12Z ritt $ |
| */ |
| #include <stdio.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <math.h> |
| typedef struct { |
| char tag[3]; |
| char version; |
| } FHEADER; |
| typedef struct { |
| char time_header[4]; |
| } THEADER; |
| typedef struct { |
| char bn[2]; |
| unsigned short board_serial_number; |
| } BHEADER; |
| typedef struct { |
| char event_header[4]; |
| unsigned int event_serial_number; |
| unsigned short year; |
| unsigned short month; |
| unsigned short day; |
| unsigned short hour; |
| unsigned short minute; |
| unsigned short second; |
| unsigned short millisecond; |
| unsigned short range; |
| } EHEADER; |
| typedef struct { |
| char tc[2]; |
| unsigned short trigger_cell; |
| } TCHEADER; |
| typedef struct { |
| char c[1]; |
| char cn[3]; |
| } CHEADER; |
| /*-----------------------------------------------------------------------------*/ |
| int main(int argc, const char * argv[]) |
| { |
| FHEADER fh; |
| THEADER th; |
| BHEADER bh; |
| EHEADER eh; |
| TCHEADER tch; |
| CHEADER ch; |
| unsigned int scaler; |
| unsigned short voltage[1024]; |
| double waveform[16][4][1024], time[16][4][1024]; |
| float bin_width[16][4][1024]; |
| int i, j, b, chn, n, chn_index, n_boards; |
| double t1, t2, dt; |
| char filename[256]; |
| int ndt; |
| double threshold, sumdt, sumdt2; |
| if (argc > 1) |
| strcpy(filename, argv[1]); |
| else { |
| printf("Usage: read_binary <filename>\n"); |
| return 0; |
| } |
| // open the binary waveform file |
| FILE *f = fopen(filename, "rb"); |
| if (f == NULL) { |
| printf("Cannot find file \'%s\'\n", filename); |
| return 0; |
| } |
| // read file header |
| fread(&fh, sizeof(fh), 1, f); |
| if (fh.tag[0] != 'D' || fh.tag[1] != 'R' || fh.tag[2] != 'S') { |
| printf("Found invalid file header in file \'%s\', aborting.\n", filename); |
| return 0; |
| } |
| if (fh.version != '2') { |
| printf("Found invalid file version \'%c\' in file \'%s\', should be \'2\', aborting.\n", fh.version, filename); |
| return 0; |
| } |
| // read time header |
| fread(&th, sizeof(th), 1, f); |
| if (memcmp(th.time_header, "TIME", 4) != 0) { |
| printf("Invalid time header in file \'%s\', aborting.\n", filename); |
| return 0; |
| } |
| for (b = 0 ; ; b++) { |
| // read board header |
| fread(&bh, sizeof(bh), 1, f); |
| if (memcmp(bh.bn, "B#", 2) != 0) { |
| // probably event header found |
| fseek(f, -4, SEEK_CUR); |
| break; |
| } |
| printf("Found data for board #%d\n", bh.board_serial_number); |
| // read time bin widths |
| memset(bin_width[b], sizeof(bin_width[0]), 0); |
| for (chn=0 ; chn<5 ; chn++) { |
| fread(&ch, sizeof(ch), 1, f); |
| if (ch.c[0] != 'C') { |
| // event header found |
| fseek(f, -4, SEEK_CUR); |
| break; |
| } |
| i = ch.cn[2] - '0' - 1; |
| printf("Found timing calibration for channel #%d\n", i+1); |
| fread(&bin_width[b][i][0], sizeof(float), 1024, f); |
| // fix for 2048 bin mode: double channel |
| if (bin_width[b][i][1023] > 10 || bin_width[b][i][1023] < 0.01) { |
| for (j=0 ; j<512 ; j++) |
| bin_width[b][i][j+512] = bin_width[b][i][j]; |
| } |
| } |
| } |
| n_boards = b; |
| // initialize statistics |
| ndt = 0; |
| sumdt = sumdt2 = 0; |
| // loop over all events in the data file |
| for (n=0 ; ; n++) { |
| // read event header |
| i = (int)fread(&eh, sizeof(eh), 1, f); |
| if (i < 1) |
| break; |
| printf("Found event #%d %d %d\n", eh.event_serial_number, eh.second, eh.millisecond); |
| // loop over all boards in data file |
| for (b=0 ; b<n_boards ; b++) { |
| // read board header |
| fread(&bh, sizeof(bh), 1, f); |
| if (memcmp(bh.bn, "B#", 2) != 0) { |
| printf("Invalid board header in file \'%s\', aborting.\n", filename); |
| return 0; |
| } |
| // read trigger cell |
| fread(&tch, sizeof(tch), 1, f); |
| if (memcmp(tch.tc, "T#", 2) != 0) { |
| printf("Invalid trigger cell header in file \'%s\', aborting.\n", filename); |
| return 0; |
| } |
| if (n_boards > 1) |
| printf("Found data for board #%d\n", bh.board_serial_number); |
| // reach channel data |
| for (chn=0 ; chn<4 ; chn++) { |
| // read channel header |
| fread(&ch, sizeof(ch), 1, f); |
| if (ch.c[0] != 'C') { |
| // event header found |
| fseek(f, -4, SEEK_CUR); |
| break; |
| } |
| chn_index = ch.cn[2] - '0' - 1; |
| fread(&scaler, sizeof(int), 1, f); |
| fread(voltage, sizeof(short), 1024, f); |
| for (i=0 ; i<1024 ; i++) { |
| // convert data to volts |
| waveform[b][chn_index][i] = (voltage[i] / 65536. + eh.range/1000.0 - 0.5); |
| // calculate time for this cell |
| for (j=0,time[b][chn_index][i]=0 ; j<i ; j++) |
| time[b][chn_index][i] += bin_width[b][chn_index][(j+tch.trigger_cell) % 1024]; |
| } |
| } |
| // align cell #0 of all channels |
| t1 = time[b][0][(1024-tch.trigger_cell) % 1024]; |
| for (chn=1 ; chn<4 ; chn++) { |
| t2 = time[b][chn][(1024-tch.trigger_cell) % 1024]; |
| dt = t1 - t2; |
| for (i=0 ; i<1024 ; i++) |
| time[b][chn][i] += dt; |
| } |
| t1 = t2 = 0; |
| threshold = 0.3; |
| // find peak in channel 1 above threshold |
| for (i=0 ; i<1022 ; i++) |
| if (waveform[b][0][i] < threshold && waveform[b][0][i+1] >= threshold) { |
| t1 = (threshold-waveform[b][0][i])/(waveform[b][0][i+1]-waveform[b][0][i])*(time[b][0][i+1]-time[b][0][i])+time[b][0][i]; |
| break; |
| } |
| // find peak in channel 2 above threshold |
| for (i=0 ; i<1022 ; i++) |
| if (waveform[b][1][i] < threshold && waveform[b][1][i+1] >= threshold) { |
| t2 = (threshold-waveform[b][1][i])/(waveform[b][1][i+1]-waveform[b][1][i])*(time[b][1][i+1]-time[b][1][i])+time[b][1][i]; |
| break; |
| } |
| // calculate distance of peaks with statistics |
| if (t1 > 0 && t2 > 0) { |
| ndt++; |
| dt = t2 - t1; |
| sumdt += dt; |
| sumdt2 += dt*dt; |
| } |
| } |
| } |
| // print statistics |
| printf("dT = %1.3lfns +- %1.1lfps\n", sumdt/ndt, 1000*sqrt(1.0/(ndt-1)*(sumdt2-1.0/ndt*sumdt*sumdt))); |
| return 1; |
| } |
| /cvi/instr/drsctrl/readdata.cpp |
|---|
| 0,0 → 1,0 |
| /cvi/instr/drsctrl/startroot.bat |
|---|
| 0,0 → 1,0 |
| cmd.exe /k thisroot.bat |
| /cvi/instr/drsctrl/strlcpy.c |
|---|
| 0,0 → 1,101 |
| /********************************************************************\ |
| Name: strlcpy.c |
| Created by: Stefan Ritt |
| Copyright 2000 + Stefan Ritt |
| Contents: Contains strlcpy and strlcat which are versions of |
| strcpy and strcat, but which avoid buffer overflows |
| This file is part of MIDAS XML Library. |
| MIDAS XML Library is free software: you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| MIDAS XML Library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| You should have received a copy of the GNU General Public License |
| along with MIDAS XML Library. If not, see <http://www.gnu.org/licenses/>. |
| \********************************************************************/ |
| #include <stdio.h> |
| #include <string.h> |
| #include "strlcpy.h" |
| /* |
| * Copy src to string dst of size siz. At most siz-1 characters |
| * will be copied. Always NUL terminates (unless size == 0). |
| * Returns strlen(src); if retval >= siz, truncation occurred. |
| */ |
| #ifndef STRLCPY_DEFINED |
| size_t strlcpy(char *dst, const char *src, size_t size) |
| { |
| char *d = dst; |
| const char *s = src; |
| size_t n = size; |
| /* Copy as many bytes as will fit */ |
| if (n != 0 && --n != 0) { |
| do { |
| if ((*d++ = *s++) == 0) |
| break; |
| } while (--n != 0); |
| } |
| /* Not enough room in dst, add NUL and traverse rest of src */ |
| if (n == 0) { |
| if (size != 0) |
| *d = '\0'; /* NUL-terminate dst */ |
| while (*s++); |
| } |
| return (s - src - 1); /* count does not include NUL */ |
| } |
| /*-------------------------------------------------------------------*/ |
| /* |
| * Appends src to string dst of size siz (unlike strncat, siz is the |
| * full size of dst, not space left). At most siz-1 characters |
| * will be copied. Always NUL terminates (unless size <= strlen(dst)). |
| * Returns strlen(src) + MIN(size, strlen(initial dst)). |
| * If retval >= size, truncation occurred. |
| */ |
| size_t strlcat(char *dst, const char *src, size_t size) |
| { |
| char *d = dst; |
| const char *s = src; |
| size_t n = size; |
| size_t dlen; |
| /* Find the end of dst and adjust bytes left but don't go past end */ |
| while (n-- != 0 && *d != '\0') |
| d++; |
| dlen = d - dst; |
| n = size - dlen; |
| if (n == 0) |
| return (dlen + strlen(s)); |
| while (*s != '\0') { |
| if (n != 1) { |
| *d++ = *s; |
| n--; |
| } |
| s++; |
| } |
| *d = '\0'; |
| return (dlen + (s - src)); /* count does not include NUL */ |
| } |
| /*-------------------------------------------------------------------*/ |
| #endif // STRLCPY_DEFINED |
| /cvi/instr/drsctrl/strlcpy.h |
|---|
| 0,0 → 1,55 |
| /********************************************************************\ |
| Name: strlcpy.h |
| Created by: Stefan Ritt |
| Copyright 2000 + Stefan Ritt |
| Contents: Header file for strlcpy.c |
| This file is part of MIDAS XML Library. |
| MIDAS XML Library is free software: you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| MIDAS XML Library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| You should have received a copy of the GNU General Public License |
| along with MIDAS XML Library. If not, see <http://www.gnu.org/licenses/>. |
| \********************************************************************/ |
| #ifndef _STRLCPY_H_ |
| #define _STRLCPY_H_ |
| // some version of gcc have a built-in strlcpy |
| #ifdef strlcpy |
| #define STRLCPY_DEFINED |
| #endif |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| #ifndef EXPRT |
| #if defined(EXPORT_DLL) |
| #define EXPRT __declspec(dllexport) |
| #else |
| #define EXPRT |
| #endif |
| #endif |
| #ifndef STRLCPY_DEFINED |
| size_t EXPRT strlcpy(char *dst, const char *src, size_t size); |
| size_t EXPRT strlcat(char *dst, const char *src, size_t size); |
| #endif |
| #ifdef __cplusplus |
| } |
| #endif |
| #endif /*_STRLCPY_H_ */ |
| /cvi/instr/drsctrl/strlcpy.obj |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |
| /cvi/instr/drsctrl/thisroot.bat |
|---|
| 0,0 → 1,25 |
| @echo off |
| set MPATH=%~dp0 |
| rem set MPATH=%CD% |
| cd "\" |
| FOR /D %%x in ("Program Files*") do ( |
| cd /D %%x |
| if exist "Microsoft SDKs\Windows\v7.1A\Include" set INCLUDE=%INCLUDE%;%CD%%%x\Microsoft SDKs\Windows\v7.1A\Include |
| For /D %%G in ("Microsoft Visual Studio*") do set VC=%%x\%%G |
| cd "\" |
| ) |
| echo call "%VC%\VC\vcvarsall.bat" x86 |
| call "%VC%\VC\vcvarsall.bat" x86 |
| cd "\" |
| FOR /D %%G IN ("root*") DO SET ROOTSYS=c:\%%G |
| echo ROOTSYS= "%ROOTSYS%" |
| echo INCLUDE="%INCLUDE%" |
| echo Visual C Development environment |
| echo nmake -f Makefile.win32 |
| cd /D "%MPATH%" |
| /cvi/instr/drsctrl/timer.c |
|---|
| 0,0 → 1,142 |
| /* |
| *************************************************************************** |
| * |
| * Author: Teunis van Beelen |
| * |
| * Copyright (C) 2010, 2011, 2012 Teunis van Beelen |
| * |
| * teuniz@gmail.com |
| * |
| *************************************************************************** |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation version 2 of the License. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| *************************************************************************** |
| * |
| * This version of GPL is at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt |
| * |
| *************************************************************************** |
| */ |
| #include "timer.h" |
| void (*timer_func_handler_pntr)(void); |
| #ifdef __linux__ |
| void timer_handler(int); |
| struct itimerval timervalue; |
| struct sigaction new_handler, old_handler; |
| void timer_sig_handler(int); |
| int start_timer(int mSec, void (*timer_func_handler)(void)) |
| { |
| timer_func_handler_pntr = timer_func_handler; |
| timervalue.it_interval.tv_sec = mSec / 1000; |
| timervalue.it_interval.tv_usec = (mSec % 1000) * 1000; |
| timervalue.it_value.tv_sec = mSec / 1000; |
| timervalue.it_value.tv_usec = (mSec % 1000) * 1000; |
| if(setitimer(ITIMER_REAL, &timervalue, NULL)) |
| { |
| printf("\nsetitimer() error\n"); |
| return(1); |
| } |
| new_handler.sa_handler = &timer_sig_handler; |
| new_handler.sa_flags = SA_NOMASK; |
| if(sigaction(SIGALRM, &new_handler, &old_handler)) |
| { |
| printf("\nsigaction() error\n"); |
| return(1); |
| } |
| return(0); |
| } |
| void timer_sig_handler(int arg) |
| { |
| timer_func_handler_pntr(); |
| } |
| void stop_timer(void) |
| { |
| timervalue.it_interval.tv_sec = 0; |
| timervalue.it_interval.tv_usec = 0; |
| timervalue.it_value.tv_sec = 0; |
| timervalue.it_value.tv_usec = 0; |
| setitimer(ITIMER_REAL, &timervalue, NULL); |
| sigaction(SIGALRM, &old_handler, NULL); |
| } |
| #else |
| HANDLE win_timer; |
| VOID CALLBACK timer_sig_handler(PVOID, BOOLEAN); |
| int start_timer(int mSec, void (*timer_func_handler)(void)) |
| { |
| timer_func_handler_pntr = timer_func_handler; |
| if(CreateTimerQueueTimer(&win_timer, NULL, (WAITORTIMERCALLBACK)timer_sig_handler, NULL, mSec, mSec, WT_EXECUTEINTIMERTHREAD) == 0) |
| { |
| printf("\nCreateTimerQueueTimer() error\n"); |
| return(1); |
| } |
| return(0); |
| } |
| VOID CALLBACK timer_sig_handler(PVOID lpParameter, BOOLEAN TimerOrWaitFired) |
| { |
| timer_func_handler_pntr(); |
| } |
| void stop_timer(void) |
| { |
| DeleteTimerQueueTimer(NULL, win_timer, NULL); |
| CloseHandle(win_timer); |
| } |
| #endif |
| /cvi/instr/drsctrl/timer.h |
|---|
| 0,0 → 1,78 |
| /* |
| *************************************************************************** |
| * |
| * Author: Teunis van Beelen |
| * |
| * Copyright (C) 2010, 2011, 2012 Teunis van Beelen |
| * |
| * teuniz@gmail.com |
| * |
| *************************************************************************** |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation version 2 of the License. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| *************************************************************************** |
| * |
| * This version of GPL is at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt |
| * |
| *************************************************************************** |
| */ |
| #include <stdio.h> |
| #ifdef __linux__ |
| #include <sys/time.h> |
| #include <signal.h> |
| #else |
| /* this code only works on win2000, XP, Vista, 7 and up */ |
| /* win95, win98 and ME are not supported */ |
| /* WINVER must have value 0x500 or higher */ |
| #ifndef WINVER |
| #define WINVER 0x500 |
| #endif |
| #if WINVER < 0x500 |
| #error "WINVER is < 0x500, cannot compile for old windows versions" |
| #endif |
| #include <windows.h> |
| #endif |
| #ifndef timer_INCLUDED |
| #define timer_INCLUDED |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| int start_timer(int, void (*)(void)); |
| void stop_timer(void); |
| #ifdef __cplusplus |
| } /* extern "C" */ |
| #endif |
| #endif |
| /cvi/instr/drsctrl/timer.obj |
|---|
| Cannot display: file marked as a binary type. |
| svn:mime-type = application/octet-stream |
| Property changes: |
| Added: svn:mime-type |
| +application/octet-stream |
| \ No newline at end of property |