/cvi/instr/drsctrl/drsread.dll |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Deleted: svn:mime-type |
-application/octet-stream |
\ No newline at end of property |
/cvi/instr/drsctrl/mxml.c |
---|
File deleted |
/cvi/instr/drsctrl/timer.c |
---|
File deleted |
/cvi/instr/drsctrl/gettimeofday.c |
---|
File deleted |
\ No newline at end of file |
/cvi/instr/drsctrl/getopt_long.c |
---|
File deleted |
/cvi/instr/drsctrl/musbstd.c |
---|
File deleted |
/cvi/instr/drsctrl/mxml.h |
---|
File deleted |
/cvi/instr/drsctrl/drsread.cpp |
---|
File deleted |
\ No newline at end of file |
/cvi/instr/drsctrl/drs4.prj |
---|
File deleted |
/cvi/instr/drsctrl/timer.h |
---|
File deleted |
/cvi/instr/drsctrl/gettimeofday.h |
---|
File deleted |
\ No newline at end of file |
/cvi/instr/drsctrl/musbstd.h |
---|
File deleted |
/cvi/instr/drsctrl/Makefile |
---|
File deleted |
/cvi/instr/drsctrl/XGetopt.h |
---|
File deleted |
/cvi/instr/drsctrl/averager.h |
---|
File deleted |
/cvi/instr/drsctrl/rb.h |
---|
File deleted |
/cvi/instr/drsctrl/drsread.lib |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Deleted: svn:mime-type |
-application/octet-stream |
\ No newline at end of property |
/cvi/instr/drsctrl/drs4.c |
---|
File deleted |
/cvi/instr/drsctrl/read_binary.cpp |
---|
File deleted |
/cvi/instr/drsctrl/LinkDef.h |
---|
File deleted |
/cvi/instr/drsctrl/drs4.h |
---|
File deleted |
/cvi/instr/drsctrl/drsread.c |
---|
File deleted |
/cvi/instr/drsctrl/gui.cpp |
---|
File deleted |
/cvi/instr/drsctrl/startroot.bat |
---|
File deleted |
/cvi/instr/drsctrl/drs4.cws |
---|
File deleted |
/cvi/instr/drsctrl/DRS.cpp |
---|
File deleted |
/cvi/instr/drsctrl/drsread.h |
---|
File deleted |
/cvi/instr/drsctrl/drs4.uir |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Deleted: svn:mime-type |
-application/octet-stream |
\ No newline at end of property |
/cvi/instr/drsctrl/XGetopt.cpp |
---|
File deleted |
/cvi/instr/drsctrl/libusb-1.0/libusb.h |
---|
File deleted |
/cvi/instr/drsctrl/averager.cpp |
---|
File deleted |
/cvi/instr/drsctrl/drs.h |
---|
File deleted |
/cvi/instr/drsctrl/thisroot.bat |
---|
File deleted |
\ No newline at end of file |
/cvi/instr/drsctrl/strlcpy.c |
---|
File deleted |
/cvi/instr/drsctrl/libusb-1.0.lib |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Deleted: svn:mime-type |
-application/octet-stream |
\ No newline at end of property |
/cvi/instr/drsctrl/rb.cpp |
---|
File deleted |
/cvi/instr/drsctrl/readdata.cpp |
---|
File deleted |
/cvi/instr/drsctrl/strlcpy.h |
---|
File deleted |
/cvi/instr/drsctrl/drscl.cpp |
---|
File deleted |
/cvi/instr/drsctrl/getopt.h |
---|
File deleted |
/cvi/instr/drsctrl/daq.h |
---|
File deleted |
/cvi/instr/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/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/drs/readdata.cpp |
---|
0,0 → 1,0 |
/cvi/instr/drs/startroot.bat |
---|
0,0 → 1,0 |
cmd.exe /k thisroot.bat |
/cvi/instr/drs/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/drs/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/drs/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/drs/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/drs/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 |