/********************************************************************\ Name: HV.cc Created by: Sebastian Commichau, November 2008 commichau@phys.ethz.ch Contents: Main class for HV supply Requirements: Both libftdi and libusb are required for the communication - see manual for more details. libftdi: library for talking with FTDI USB <-> Serial converter, UM245R. http://www.intra2net.com/de/produkte/opensource/ftdi/ libusb: library for talking to USB devices from user-space. Also needed by libftdi. http://libusb.wiki.sourceforge.net/ \********************************************************************/ #include "HV.h" HV::HV(char** usbdevice, int* usbdevicenumber, FILE* f): fNumberOfBoards(0) { int i = 0, j = 0, ret = 0; char manufacturer[STR_LENGTH], type[STR_LENGTH], serial[STR_LENGTH]; bzero(manufacturer, sizeof(manufacturer)); bzero(type, sizeof(type)); bzero(serial, sizeof(serial)); fprintf(stdout,"Scan: "); // Search for FTDI devices for (i = 0;idev, manufacturer, STR_LENGTH, type, STR_LENGTH, serial, STR_LENGTH)) < 0) { fprintf(stderr," Error: ftdi_usb_get_strings failed: %d (%s)\n", ret, ftdi_get_error_string(&ftdic_dummy)); break; } fprintf(stdout," Manufacturer: %s - Type: %s - Serial: %s\n", manufacturer, type, serial); // Fixme: the following code should be revised! while (jnext; } // Re-order board numbering otherwise it is determined by the connection sequence ArrangeHVBoards(fHVBoard,fNumberOfBoards); } /* Bubble-sort HV boards according to board number */ void HV::ArrangeHVBoards(HVBoard** fHVBoard, int size) { HVBoard* tmp; for (int i=size-1;i>0;--i) for (int pos=0;posGetBoardNumber()>fHVBoard[pos+1]->GetBoardNumber()) { tmp = fHVBoard[pos]; fHVBoard[pos] = fHVBoard[pos+1]; fHVBoard[pos+1] = tmp; } } HV::~HV() { int i, ret = 0; for (i=0;i= fTimeOut) { fprintf(fptr," Warning: timeout exceeded\n"); return -1; } } while(1); } /* Reset HV board - uses TRead() and has same return values */ int HVBoard::Reset(FILE* fptr, unsigned char* rbuf, bool verbose) { char str[STR_LENGTH]; unsigned char wbuf[] = {REG_RESET,0,0}; if (Write(wbuf,3) < 1) { fprintf(fptr," Error: could not write to HV board\n"); return 0; } if (verbose) fprintf(fptr," 3 bytes written:\n"); for (int i=0;i<3;i++) { sPrintByteBin(wbuf[i],str); if (verbose) fprintf(fptr," Byte %d: %s| 0X%.2X\n",i,str,wbuf[i]); } return TRead(fptr,rbuf,verbose); } /* Read status register - uses TRead() and has same return values */ int HVBoard::GetStatus(FILE* fptr, unsigned char* rbuf, bool verbose) { char str[STR_LENGTH]; unsigned char wbuf[] = {REG_STATUS,0,0}; if (Write(wbuf,3) < 1) { if (verbose) fprintf(fptr," Error: could not write to HV board\n"); return 0; } if (verbose) fprintf(fptr," 3 bytes written:\n"); for (int i=0;i<3;i++) { sPrintByteBin(wbuf[i],str); if (verbose) fprintf(fptr," Byte %d: %s| 0X%.2X\n",i,str,wbuf[i]); } return TRead(fptr,rbuf,verbose); } /* Set high voltage - uses TRead() and has same return values */ int HVBoard::SetHV(FILE* fptr, int chain, unsigned int channel, unsigned int hv, unsigned char* rbuf, bool verbose) { char str[STR_LENGTH]; unsigned char wbuf[] = {0,0,0}; if (!(hv>=0.0 && hv<=0X3FFF)) { fprintf(fptr," Error: HV beyond limits [0 - 0x3FFF]\n"); return 0; } switch (chain) { case 0: wbuf[0] = REG_HV0; break; case 1: wbuf[0] = REG_HV1; break; case 2: wbuf[0] = REG_HV2; break; case 3: wbuf[0] = REG_HV3; break; default : fprintf(fptr," Error: chain %d does not exist\n",chain); return 0; } // Assemble bytes wbuf[0] |= (unsigned char)((channel >> 2) & 0X00000007); // Add address [A4-A3] wbuf[1] |= (unsigned char)((hv >> 8) & 0X000000FF); // Add [D13-D8] wbuf[1] |= (unsigned char)((channel << 6) & 0X000000C0); // Add [A1-A0] wbuf[2] |= (unsigned char)(hv & 0X000000FF); // Add [D7-D0] if (Write(wbuf,3) < 1) { fprintf(fptr," Error: could not write to HV board\n"); return 0; } if (verbose) fprintf(fptr," 3 bytes written:\n"); for (int i=0;i<3;i++) { sPrintByteBin(wbuf[i],str); if (verbose) fprintf(fptr," Byte %d: %s| 0X%.2X\n",i,str,wbuf[i]); } return TRead(fptr,rbuf,verbose); } /* Set reference voltage - uses TRead() and has same return values */ int HVBoard::SetVRef(FILE* fptr, int chain, unsigned int vref, unsigned char* rbuf, bool verbose) { char str[STR_LENGTH]; unsigned char wbuf[] = {0,0,0}; if (!(vref>=0 && vref<=0X3FFF)) { if (verbose) fprintf(fptr," Error: vref beyond limits\n"); return 0; } switch (chain) { case 0: wbuf[0] = REG_VREF0; break; case 1: wbuf[0] = REG_VREF1; break; case 2: wbuf[0] = REG_VREF2; break; case 3: wbuf[0] = REG_VREF3; break; default : fprintf(fptr," Error: chain %d does not exist\n",chain); return 0; } // Assemble bytes wbuf[0] |= (unsigned char)((vref >> 13) & 0X0000000F); // Add [D13] wbuf[1] |= (unsigned char)((vref >> 5) & 0X000000FF); // Add [D12-D5] wbuf[2] |= (unsigned char)((vref << 3) & 0X000000FF); // Add [D4-D0] // PD bits (device clear) are not used wbuf[0] &= ~REG_PD1; wbuf[0] &= ~REG_PD2; if (Write(wbuf,3) < 1) { fprintf(fptr," Error: could not write to HV board\n"); return 0; } if (verbose) fprintf(fptr," 3 bytes written:\n"); for (int i=0;i<3;i++) { sPrintByteBin(wbuf[i],str); if (verbose) fprintf(fptr," Byte %d: %s| 0X%.2X\n",i,str,wbuf[i]); } return TRead(fptr,rbuf,verbose); } /* Init: initialize (synchronize) HV board - to be used before any other access! Returns 0 if an error has occured, 1 on success. Before any other access the HV board communication has to be synchronized. Each write access requires three bytes to be sent from the computer to the HV board. The HV board sends back one byte containing status information. The normal initialization procedure would be the following: 1. send one byte (0X80 = REG_STATUS). 1.1. try reading as long as fTimeOut is not exceeded. 2. send again one byte (0X00). 2.1. try reading as long as fTimeOut is not exceeded. 3. send again one byte (0X00). 3.1. try reading again as long as fTimeOut is not exceeded. Note: from time to time there are problems when performing only 3 trials! Reason: the first byte written by libftdi can get lost somewhere between libusb <-> kernel <-> FTDI chip. I haven't found yet any solution to this. To solve the issue, another byte is sent to assure a proper synchronization, even though the first byte was lost: 4. send again one byte (0X00). 4.1. try reading again as long as fTimeOut is not exceeded; if fTimeOut has been exceeded return. See also: http://lists.omnipotent.net/pipermail/lcdproc/2008-June/012235.html */ int HVBoard::Init(bool verbose) { unsigned char wbuf = REG_STATUS; unsigned char rbuf[STR_LENGTH]; int trial = 1; int ret = 0; long int t1, t2; // First send 0X80 if (Write(&wbuf,1) < 1) { if (verbose) fprintf(stdout," Error: could not write to HV board\n"); return 0; } else if (verbose) fprintf(stdout," 1 byte written: 0X%.2X\n",wbuf); t1 = GetMicroSeconds(); // Read - first trial do { t2 = GetMicroSeconds(); if ((ret = Read(rbuf,BUFFER_LENGTH)) < 1) { if (verbose) if (ret < 0) { fprintf(stderr, " Read error: %d (%s)\n",ret,ftdi_get_error_string(FTDI_C)); return 0; } } else { if (verbose) fprintf(stdout," %d byte(s) read:",ret); for (int i=0;i fTimeOut) { if (verbose) fprintf(stdout," Warning: timeout exceeded\n"); trial++; // Second write wbuf = 0; if (Write(&wbuf,1) < 1) { if (verbose) fprintf(stdout," Error: could not write to HV board\n"); return 0; } else if (verbose) fprintf(stdout," 1 byte written: 0X%.2X\n",wbuf); t1 = GetMicroSeconds(); // Read - second trial do { t2 = GetMicroSeconds(); if ((ret = Read(rbuf,BUFFER_LENGTH)) < 1) { if (verbose) if (ret < 0) { fprintf(stderr, " Read error: %d (%s)\n",ret,ftdi_get_error_string(FTDI_C)); return 0; } } else { if (verbose) fprintf(stdout," %d byte(s) read:",ret); for (int i=0;i fTimeOut) { if (verbose) fprintf(stdout," Warning: timeout exceeded\n"); trial++; // Third write wbuf = 0; if (Write(&wbuf,1) < 1) { if (verbose) fprintf(stdout," Error: could not write to HV board\n"); return 0; } else if (verbose) fprintf(stdout," 1 byte written: 0X%.2X\n",wbuf); // Read - third trial do { t2 = GetMicroSeconds(); if ((ret = Read(rbuf,BUFFER_LENGTH)) < 1) { if (verbose) if (ret < 0) { fprintf(stderr, " Read error: %d (%s)\n",ret,ftdi_get_error_string(FTDI_C)); return 0; } } else { if (verbose) fprintf(stdout," %d byte(s) read:",ret); for (int i=0;i fTimeOut) { if (verbose) fprintf(stdout," Warning: timeout exceeded\n"); trial++; // Fourth write wbuf = 0; if (Write(&wbuf,1) < 1) { if (verbose) fprintf(stdout," Error: could not write to HV board\n"); return 0; } else if (verbose) fprintf(stdout," 1 byte written: 0X%.2X\n",wbuf); // Read - fourth and last trial do { t2 = GetMicroSeconds(); if ((ret = Read(rbuf,BUFFER_LENGTH)) < 1) { if (verbose) if (ret < 0) { fprintf(stderr, " Read error: %d (%s)\n",ret,ftdi_get_error_string(FTDI_C)); return 0; } } else { if (verbose) fprintf(stdout," %d byte(s) read:",ret); for (int i=0;i fTimeOut) { if (verbose) fprintf(stdout," Error: timeout exceeded - initialization failed (%d trials)\n",trial); return 0; } } while (1); } } while (1); } } while (1); } } while (1); return 0; } /* Decode wrap counter */ int HVBoard::DecodeWrap(unsigned char* rbuf) { return (*rbuf & 0X07); } /* Decode over current bits */ void HVBoard::DecodeOC(bool OC[], unsigned char* rbuf) { for (int i=0;i