/********************************************************************\ HVFeedback.cc Class handling the feedback of GAPD high voltage Oliver Grimm \********************************************************************/ #include "HVFeedback.h" #include "PixelMap.h" #include #include #include #define PIXMAP_LOCATION "../config/PixelMap.txt" // // Constructor: Initialise feedback // HVFeedback::HVFeedback(DAQReadout* DAQClass, char* Configfile) { struct sockaddr_in SocketAddress; m = DAQClass; PixMap = new PixelMap(PIXMAP_LOCATION, false); // Create instance of slow data class for feedback SlowDataClass = new SlowData("HVFB", m->fSlowDataPath); if (SlowDataClass->ErrorCode != 0) { m->PrintMessage("Warning: Could not open feedback slowdata file (%s)\n", strerror(SlowDataClass->ErrorCode)); } SlowDataClass->NewEntry("Average-Info", "Feedback regulation occurred: Board Chip Channel Average Sigma Correction-Value"); SlowDataClass->NewEntry("Target-Info", "New Target values acquired: Board Chip Channel Target Sigma"); SlowDataClass->NewEntry("Response-Info", "New response measurement: Board Chip Channel Response"); // Initialise with zero content Average = new float [m->NumBoards][kNumberOfChips][kNumberOfChannels](); Sigma = new float [m->NumBoards][kNumberOfChips][kNumberOfChannels](); Response = new float [m->NumBoards][kNumberOfChips][kNumberOfChannels](); Target = new float [m->NumBoards][kNumberOfChips][kNumberOfChannels](); Buffer = new float [m->NumBoards][kNumberOfChips][kNumberOfChannels](); // Read configuration file FILE *File; if ((File = fopen(Configfile,"r")) == NULL) { printf("Error: Could not open feedback configuration file '%s'\n", Configfile); } else { printf("Reading feedback configuration file %s\n", Configfile); ReadCard("TrigBoard", &fLedTrigBoard, 'I', File); ReadCard("TrigChannel", &fLedTrigChannel, 'I', File); ReadCard("TrigChip", &fLedTrigChip, 'I', File); ReadCard("TrigSample", &fLedTrigSample, 'I', File); ReadCard("TrigThreshold", &fLedTrigThreshold, 'f', File); ReadCard("SignalSample", &fLedSignalSample, 'I', File); ReadCard("BaselineSample", &fLedBaselineSample, 'I', File); ReadCard("IntHalfWidth", &fIntHalfWidth, 'U', File); ReadCard("DefaultNumAverage", &fDefaultNumAverage, 'I', File); ReadCard("HVControlServer", fHVControlServer, 's', File); ReadCard("HVControlPort", &fHVControlPort, 'I', File); ReadCard("MaxCmdAckDelay", &fMaxCmdAckDelay, 'I', File); ReadCard("DefaultResponse", Response, 'f', File, m->NumBoards*kNumberOfChips*kNumberOfChannels); ReadCard("DefaultTarget", Target, 'f', File, m->NumBoards*kNumberOfChips*kNumberOfChannels); // Add also initial gain to configuration parameters fclose(File); } PrintConfig(MsgToLog); // Initial state Gain = 0.2; SetFBMode(FB_Off); SetNumAverages(fDefaultNumAverage); // Opening socket client to HV control program if ((SocketDescriptor = socket(PF_INET, SOCK_STREAM, 0)) == -1) m->PrintMessage("Could not open client socket, no HV control available.\n"); // Resolve hostname and try to connect to server struct hostent *hostent = gethostbyname(fHVControlServer); if (hostent==0) m->PrintMessage("Could not resolve HV server host name \"%s\".\n", fHVControlServer); else { SocketAddress.sin_family = PF_INET; SocketAddress.sin_port = htons((unsigned short) fHVControlPort); SocketAddress.sin_addr = *(struct in_addr*) hostent->h_addr; if (connect(SocketDescriptor, (struct sockaddr *) &SocketAddress, sizeof(SocketAddress))==-1) m->PrintMessage("Could not connect to HV server %s at port %d (%s)\n", fHVControlServer, fHVControlPort, strerror(errno)); else m->PrintMessage("\nFeedback connected to HV server %s (port %d).\n", fHVControlServer, fHVControlPort); signal(SIGPIPE,SIG_IGN); // Do not kill process if writing to closed socket } } // // Destructor // HVFeedback::~HVFeedback() { if (SocketDescriptor!=-1) { close(SocketDescriptor); m->PrintMessage("Feedback socket closed.\n"); } delete[] Average; delete[] Response; delete[] Target; delete[] Buffer; delete SlowDataClass; delete PixMap; } // // Check if LED trigger present, if yes accumulate feedback data and // calculate new high voltages if the required number of events is reached. // bool HVFeedback::ProcessEvent() { int i,j,k,q; float Correction, Integral, Difference; // Check for LED trigger channel on given channel and if feedback running if (FBMode==FB_Off || m->WaveForm[fLedTrigBoard][fLedTrigChip][fLedTrigChannel][(fLedTrigSample+m->TriggerCell[fLedTrigBoard][fLedTrigChip])%kNumberOfBins] < fLedTrigThreshold) return false; // Calculate average signal of LED pulse as integral of signal for (i=m->FirstBoard; i<=m->LastBoard; i++) for (j=0; jWaveForm[i][j][k][(fLedSignalSample+q+m->TriggerCell[i][j])%kNumberOfBins] - m->WaveForm[i][j][k][(fLedBaselineSample+q+m->TriggerCell[i][j])%kNumberOfBins])*m->drs->GetBoard(i)->GetPrecision(); Integral /= 2*fIntHalfWidth+1; Average[i][j][k] += Integral; Sigma[i][j][k] += pow(Integral,2); } // Check if acquired number of event requires action if (++CountNewEntry("Average"); break; case FB_Targets: SlowDataClass->NewEntry("Target"); break; case FB_ResponseSecond: SlowDataClass->NewEntry("Response"); SlowDataClass->AddToEntry("%.3f ",DiffVoltage); break; default: break; // to suppress warning abount not handled enumeration value } // Feedback action for (i=m->FirstBoard; i<=m->LastBoard; i++) { for (j=0; j 0.1) Correction = fabs(Correction)/Correction*0.1; // Limit changes to 100 mV if(Correction!=0 && Target[i][j][k]!=0 && !PixMap->DRS_to_Pixel(i,j,k).empty()) { printf("Average of board %d, chip %d, channel %d is %.2f +/- %.2f Correction %.3f\n",i,j,k,Average[i][j][k],Sigma[i][j][k],Correction); SlowDataClass->AddToEntry("%d %d %d %.3f %.3f %.3f ", i,j,k,Average[i][j][k],Sigma[i][j][k],Correction); if(fabs(Average[i][j][k]) < 2*Sigma[i][j][k]) printf("Too noisy!\n"); else WriteHVCommand("hvdiff %s %f\n",PixMap->DRS_to_Pixel(i,j,k).c_str(),Correction); } break; case FB_Targets: // Take average as new targets Target[i][j][k] = Average[i][j][k]; SlowDataClass->AddToEntry("%d %d %d %.3f %.3f ", i,j,k,Average[i][j][k],Sigma[i][j][k]); break; case FB_ResponseFirst: // First point of response measurement done Buffer[i][j][k] = Average[i][j][k]; if(!PixMap->DRS_to_Pixel(i,j,k).empty()) WriteHVCommand("hvdiff %s %f",PixMap->DRS_to_Pixel(i,j,k).c_str(), DiffVoltage); break; case FB_ResponseSecond: // Determine response from signal variation if(Buffer[i][j][k] == Average[i][j][k]) { m->PrintMessage("HV Feedback: Warning, response singular for board %d, chip %d, channel %d.\n",i,j,k); Response[i][j][k] = 0; } else Response[i][j][k] = DiffVoltage/(Buffer[i][j][k]-Average[i][j][k]); SlowDataClass->AddToEntry("%d %d %d %.3f ", i,j,k,Response[i][j][k]); if(!PixMap->DRS_to_Pixel(i,j,k).empty()) WriteHVCommand("hvdiff %s %f",PixMap->DRS_to_Pixel(i,j,k).c_str(), -DiffVoltage/2); break; default: break; // to suppress warning abount not handled enumeration value } } } } switch (FBMode) { case FB_Targets: m->PrintMessage("HV Feedback: New targets set, switching off.\n"); FBMode = FB_Off; break; case FB_ResponseFirst: FBMode = FB_ResponseSecond; m->PrintMessage("HV Feedback: Increasing voltages by %f for response measurement, acquiring data.\n", DiffVoltage); break; case FB_ResponseSecond: m->PrintMessage("HV Feedback: Response measurements finished, original voltages set, switching off.\n"); FBMode = FB_Off; break; default: break; // to suppress warning abount not handled enumeration value } if(m->SlowDataClass->ErrorCode != 0) { m->PrintMessage("Error, could not write feedback slow data to file (%s), file closed.\n", strerror(m->SlowDataClass->ErrorCode)); } ClearAverages(); return true; } // // Clear average values and event counter // void HVFeedback::ClearAverages() { for (int i=m->FirstBoard; i<=m->LastBoard; i++) for (int j=0; jPrintMessage("Start reponse measurement by calling MeasureResponse().\n"); else { FBMode = Mode; ClearAverages(); } } // // Get feedback mode // FBState HVFeedback::GetFBMode() { switch (FBMode) { case FB_Off: m->PrintMessage("Feedback off.\n"); break; case FB_Active: m->PrintMessage("Feedback active.\n"); break; case FB_Targets: m->PrintMessage("Feedback acquiring new targets.\n"); break; case FB_ResponseFirst: m->PrintMessage("Feedback measuring response with first voltage.\n"); break; case FB_ResponseSecond: m->PrintMessage("Feedback measuring response with second voltage.\n"); break; } return FBMode; } // // Return current number of events // unsigned int HVFeedback::GetCurrentCount() { return Count; } // // Set target values // void HVFeedback::SetTarget(int Board, int Chip, int Channel, float TargetVal) { if(BoardNumBoards && ChipFirstBoard; i<=m->LastBoard; i++) for (int j=0; jPrintMessage("Board %d, chip %d:",i,j); for (int k=0; kPrintMessage(" %.2f",Target[i][j][k]); m->PrintMessage("\n\r"); } } // // Measure response matrix // void HVFeedback::MeasureResponse(float U) { if (U==0) { m->PrintMessage("HV Feedback: Error, voltage difference must not non-zero.\n"); return; } for (int i=m->FirstBoard; i<=m->LastBoard; i++) for (int j=0; jDRS_to_Pixel(i,j,k).empty()) { WriteHVCommand("hvdiff %s %f\n",PixMap->DRS_to_Pixel(i,j,k).c_str(), -U/2); } } DiffVoltage = U; FBMode = FB_ResponseFirst; ClearAverages(); m->PrintMessage("HV Feedback: Decreasing voltages by %f for response measurement, acquiring data.\n",DiffVoltage/2); } // // Print response values // void HVFeedback::GetResponse() { for (int i=m->FirstBoard; i<=m->LastBoard; i++) { for (int j=0; jPrintMessage("Board %d, chip %d:",i,j); for (int k=0; kPrintMessage(" %.3f",Response[i][j][k]); m->PrintMessage("\n\r"); } } } // // Write commmand to socket // bool HVFeedback::WriteHVCommand(const char *Format, ...) { char Textbuffer[MAX_COM_SIZE]; fd_set SelectDescriptor; va_list ArgumentPointer; va_start(ArgumentPointer, Format); vsnprintf(Textbuffer, sizeof(Textbuffer), Format, ArgumentPointer); // Write command to socket if(write(SocketDescriptor, Textbuffer, strlen(Textbuffer)+1)!=(int) strlen(Textbuffer)+1) { m->PrintMessage("Error: Could not write (entire) command to HV socket (%s)\n", strerror(errno)); return false; } // Wait for command acknowledge from hvcontrol program FD_ZERO(&SelectDescriptor); FD_SET(SocketDescriptor, &SelectDescriptor); struct timeval WaitTime = {fMaxCmdAckDelay, 0}; if (select(((int) SocketDescriptor)+1, &SelectDescriptor, NULL, NULL, &WaitTime)==-1) { m->PrintMessage("Error with select() in command acknowledge (%s)\n", strerror(errno)); return false; } // Evaluate response if (!FD_ISSET(SocketDescriptor, &SelectDescriptor)) { // Time-out m->PrintMessage("Time-out of %d seconds expired before receiving acknowledge from HV socket.\n", fMaxCmdAckDelay); return false; } if (read(SocketDescriptor, Textbuffer, MAX_COM_SIZE) == -1) { // Could not read m->PrintMessage("Error reading acknowledge from HV socket (%s)\n", strerror(errno)); return false; } if (strncmp(Textbuffer, "OK", 2) != 0) { // ERROR response m->PrintMessage("Did not received OK from hvcontrol.\n"); return false; } return true; } // // Print feedback configuration // void HVFeedback::PrintConfig(int Target) { m->PrintMessage(Target, "LedTrigBoard: %d\t\tLedTrigChip: %d\t\tLedTrigChannel: %d\n" "LedTrigSample: %d\tLedTrigThreshold: %.2f\n" "LedSignalSample: %d\tLedBaselineSample: %d\tDefaultNumAverage: %d\n" "IntHalfWidth:%u\tHVControlServer: %s\tHVControlPort: %d\n" "MaxCmdAckDelay: %d\n", fLedTrigBoard, fLedTrigChip, fLedTrigChannel, fLedTrigSample, fLedTrigThreshold, fLedSignalSample, fLedBaselineSample, fDefaultNumAverage, fIntHalfWidth, fHVControlServer, fHVControlPort, fMaxCmdAckDelay); }