/********************************************************************\ FAD.cc Main class of FADCtrl Comment 19/10/2010: It is assumed that boolean access is an atomic operation. \********************************************************************/ #include "FAD.h" using namespace std; static const struct CL_Struct { const char *Name; void (FAD::*CommandPointer)(); bool NeedIdle; unsigned int MinNumParameter; const char *Parameters; const char *Help; } CommandList[] = {{"board", &FAD::cmd_board, true, 1, "[+|-]" ,"Activate or deactivate boards"}, {"status", &FAD::cmd_status, false, 0, "[range]", "Show board status information"}, {"domino", &FAD::cmd_domino, true, 1, "", "Switch Domino wave"}, {"dwrite", &FAD::cmd_dwrite, true, 1, "", "Set DWRITE"}, {"phase", &FAD::cmd_phase, true, 1, "", "Adjust ADC phase (in 'steps')"}, {"srclk", &FAD::cmd_srclk, true, 1, "", "Set SRCLK"}, {"sclk", &FAD::cmd_sclk, true, 1, "", "Set SCLK"}, {"trigger", &FAD::cmd_trigger, false, 0, "[n|cont|stop]", "Issue software triggers"}, {"roi", &FAD::cmd_roi, true, 2, " ", "Set region-of-interest to value"}, {"dac", &FAD::cmd_dac, true, 2, " ", "Set DAC numbers in range to value"}, {"address", &FAD::cmd_address, true, 2, " ", "Set addresses in range to value"}, {"send", &FAD::cmd_send, true, 1, "", "Set arbitrary data to board"}, {"acalib", &FAD::cmd_acalib, true, 0, "", "Amplitude calibration"}, //{"tcalib", &FAD::cmd_tcalib, 1, " ", "Time calibration"}, //{"wmode", &FAD::cmd_wmode, 0, "", "Domino wave running or stopped during read out"}, //{"rmode", &FAD::cmd_rmode, 0, "", "Readout start at first bin or stop position (DRS4)"}, //{"dmode", &FAD::cmd_dmode, 0, "", "Domino wave single shot or continuous"}, {"cancel", &FAD::cmd_cancel, false, 0, "", "Cancel current operation"}, {"update", &FAD::cmd_update, false, 1, "", "Minimum delay between updates to DIM event service"}, {"exit", &FAD::cmd_exit, true, 0, "", "Exit program"}, {"help", &FAD::cmd_help, false, 0, "", "Print help"}}; // ------------------------------------ // ***** Constructor/Destructor ***** // ------------------------------------ // // Constructor // FAD::FAD(): EvidenceServer(SERVER_NAME) { // Initialization ConsoleText = NULL; MainThread = pthread_self(); Mode = idle; EventUpdateDelay = atof(GetConfig("EventUpdateDelay", "0.5").c_str())*1e6; // DIM console service used in PrintMessage() ConsoleOut = new DimService(SERVER_NAME"/ConsoleOut", (char *) ""); // Get configuration data (static needed for c_str() pointers to remain valid after constructor finished) //static string _CalibDataPath = GetConfig("CalibDataPath"); //fCalibDataPath = _CalibDataPath.c_str(); //snprintf(CalibInfoFilename,sizeof(CalibInfoFilename), "%s/CalibInfo", fCalibDataPath); // Construct boards BoardList = Tokenize(GetConfig("BoardList","192.33.99.225")); for (unsigned int i=0; iInitOK) { Message(WARN, "Failed to initialize board %s\n", BoardList[i].c_str()); delete Boards.back(); Boards.pop_back(); } } // Create DIM event service thread int Ret; if ((Ret = pthread_create(&Thread, NULL, (void * (*)(void *)) LaunchEventThread,(void *) this)) != 0) { Message(ERROR, "pthread_create() failed in FAD::FAD() (%s)", strerror(Ret)); Thread = pthread_self(); } // Install DIM command (after all initialized) Command = new DimCommand((char *) SERVER_NAME"/Command", (char *) "C", this); } // // Destructor // FAD::~FAD() { int Ret; // Delete all boards (cancels threads automatically) for (unsigned int i=0; igetString(); // Ignore empty or illegal strings if (getCommand()->getSize() == 0 || *(Command+getCommand()->getSize()-1) != '\0' || strlen(Command) == 0) return; // Shell command if (Command[0]=='.') { system(&(Command[1])); return; } // Parse command into tokens Parameter.clear(); char *Start; while(true) { while (isspace(*Command)) Command++; // Ignore initial white spaces if(*Command=='\0') break; if (*Command == '\"') { Start = ++Command; while(*Command!='\"' && *Command!='\0') Command++; } else { Start = Command; while(!isspace(*Command) && *Command!='\0') Command++; } if(*Command != '\0') *Command++ = '\0'; Parameter.push_back(Start); } // Search for command in command list for(unsigned int i=0; i*CommandList[i].CommandPointer)(); return; } } PrintMessage("Unknown command '%s'\n", Parameter[0].c_str()); } // // Switch SRCLK // void FAD::cmd_srclk() { for (unsigned int i=0; iSend(CMD_SRCLK_ON); else if (Match(Parameter[1],"off")) Boards[i]->Send(CMD_SRCLK_OFF); } if (Match(Parameter[1],"on")) PrintMessage("SRCLK switched on for all active boards\n"); else if (Match(Parameter[1],"off")) PrintMessage("SRCLK switched off for all active boards\n"); else PrintUsage(); } // // Switch SCLK // void FAD::cmd_sclk() { for (unsigned int i=0; iSend(CMD_SCLK_ON); else if (Match(Parameter[1],"off")) Boards[i]->Send(CMD_SCLK_OFF); } if (Match(Parameter[1],"on")) PrintMessage("SCLK switched on for all active boards\n"); else if (Match(Parameter[1],"off")) PrintMessage("SCLK switched off for all active boards\n"); else PrintUsage(); } // // Switch Domino wave // void FAD::cmd_domino() { for (unsigned int i=0; iSend(CMD_DENABLE); else if (Match(Parameter[1],"off")) Boards[i]->Send(CMD_DDISABLE); } if (Match(Parameter[1],"on")) PrintMessage("Domino wave switched on for all active boards\n"); else if (Match(Parameter[1],"off")) PrintMessage("Domino wave switched off for all active boards\n"); else PrintUsage(); } // // Switch DWRITE // void FAD::cmd_dwrite() { for (unsigned int i=0; iSend(CMD_DWRITE_RUN); else if (Match(Parameter[1],"off")) Boards[i]->Send(CMD_DWRITE_STOP); } if (Match(Parameter[1],"on")) PrintMessage("DWRITE set high for all active boards\n"); else if (Match(Parameter[1],"off")) PrintMessage("DWRITE set low for all active boards\n"); else PrintUsage(); } // // Issue soft trigger // void FAD::cmd_trigger() { int Num; for (unsigned int i=0; iSend(CMD_Trigger); else if (ConvertToInt(Parameter[1], &Num)) { for (int j=0; jSend(CMD_Trigger); usleep(10000); } } else if (Match(Parameter[1],"continuous")) Boards[i]->Send(CMD_Trigger_C); else if (Match(Parameter[1],"stop")) Boards[i]->Send(CMD_Trigger_S); else { PrintUsage(); break; } } } // // Set DAC // void FAD::cmd_dac() { int Value; struct Range R = {0, NDAC-1}; unsigned short Buffer[2*NDAC] = {0}; // Check ranges if(!ConvertToRange(Parameter[1], R)) { PrintMessage("Error, DAC number out of range.\n"); return; } if (!ConvertToInt(Parameter[2], &Value) || Value<0 || Value>MAX_DACVAL) { PrintMessage("Error, DAC value out of range.\n"); return; } // Prepare command buffer for (int i=R.Min; i<=R.Max; i++) { Buffer[2*i] = htons(CMD_Write | (BADDR_DAC + i)); Buffer[2*i+1] = htons(Value); } // Send command buffer for (unsigned int i=0; iSend(Buffer, sizeof(Buffer)); } } // // Set region-of-interest // void FAD::cmd_roi() { int Value; struct Range R = {0, NChips*NChannels-1}; unsigned short Buffer[2*NChips*NChannels] = {0}; // Check ranges if (!ConvertToRange(Parameter[1], R)) { PrintMessage("Error, ROI number out of range.\n"); return; } if (!ConvertToInt(Parameter[2], &Value) || Value<0 || Value>MAX_ROIVAL) { PrintMessage("Error, ROI value out of range.\n"); return; } // Prepare command buffer for (int i=R.Min; i<=R.Max; i++) { Buffer[2*i] = htons(CMD_Write | (BADDR_ROI + i)); Buffer[2*i+1] = htons(Value); } // Send command buffer for (unsigned int i=0; iSend(Buffer, sizeof(Buffer)); } } // // Set addresses to value // void FAD::cmd_address() { int Value; struct Range R = {0, MAX_ADDR}; unsigned short Buffer[2*MAX_ADDR] = {0}; // Check ranges if (!ConvertToRange(Parameter[1], R)) { PrintMessage("Error, address out of range.\n"); return; } if (!ConvertToInt(Parameter[2], &Value) || Value<0 || Value>MAX_VAL) { PrintMessage("Error, value out of range.\n"); return; } // Prepare command buffer for (int i=R.Min; i<=R.Max; i++) { Buffer[2*i] = htons(CMD_Write | i); Buffer[2*i+1] = htons(Value); } // Send command buffer for (unsigned int i=0; iSend(Buffer, 2*(R.Max-R.Min+1)*sizeof(unsigned short)); } } // // Set ADC phase // void FAD::cmd_phase() { int Value; if (!ConvertToInt(Parameter[1], &Value)) { PrintMessage("Error, illegal phase value\n"); return; } // Prepare command buffer unsigned short *Buffer = new unsigned short [abs(Value)]; for (int i=0; iSend(CMD_PS_RESET); if (Value < 0) Boards[i]->Send(CMD_PS_DIRDEC); else Boards[i]->Send(CMD_PS_DIRINC); Boards[i]->Send(Buffer, abs(Value)*sizeof(unsigned short)); } delete[] Buffer; } // // Send arbitrary data to board // void FAD::cmd_send() { int Value; if (!ConvertToInt(Parameter[1], &Value) || Value<0 || Value>MAX_VAL) { PrintMessage("Error, illegal value\n"); return; } for (unsigned int i=0; iSend(Value); } /* // Set Domino mode void FAD::cmd_dmode() { if (Match(Param[1],"continuous")) SetDOMINOMode(1); else if (Match(Param[1],"single")) SetDOMINOMode(0); else PrintUsage(); } // Set Domino readout mode void FAD::cmd_rmode() { if (Match(Param[1],"first")) SetDOMINOReadMode(0); else if (Match(Param[1],"stop")) SetDOMINOReadMode(1); else PrintUsage(); } // Set Domino wave mode void FAD::cmd_wmode() { if (Match(Param[1],"run")) SetDOMINOWaveMode(1); else if (Match(Param[1],"stop")) SetDOMINOWaveMode(0); else PrintUsage(); } */ // // Amplitude calibration // void FAD::cmd_acalib() { pthread_t Thread; int Code; // Set mode before lunching thread Mode = acalib; Cancel = false; // Create detached thread if ((Code = pthread_create(&Thread, NULL, (void * (*)(void *)) FAD::LaunchAmplitudeCalibration,(void *) this)) != 0) { Message(ERROR, "pthread_create() failed in FAD::cmd_acalib() (%s)\n", strerror(Code)); Mode = idle; return; } if ((Code = pthread_detach(Thread)) != 0) { Message(ERROR, "pthread_detach() failed in FAD::cmd_acalib() (%s)\n", strerror(Code)); } } /* // Do time calibration void FAD::cmd_tcalib() { if (!IsDRSFreqSet()) { PrintMessage("Set sampling frequency for all boards first\n"); return; } if (!ReadCalibration()) { PrintMessage("Amplitude calibration has to be done first\n"); return; } for (int i=FirstBoard; i<=LastBoard; i++) { if (GetBoard(i)->GetDRSType() != 4 || GetBoard(i)->GetFirmwareVersion() < 13279) { PrintMessage("Time calibration needs DRS4 and minimum firmware version 13279, skipping board %d\n", i); continue; } PrintMessage("Creating time calibration of board %d (serial #%04d)\n Note: No input signals should be connected\n", i, GetBoard(i)->GetBoardSerialNumber()); GetBoard(i)->SetFrequency(DRSFreq[i], true); if (GetBoard(i)->CalibrateTiming(this) != 1) { PrintMessage("Time calibration method returned error status, stopping calibration\n"); return; } TCalib[i] = true; // Write calibration data to file float Time[NChipsMax][NBins]; char *Filename; FILE *Calibfile; bool WriteOK = true; // Copy calibration data into array for (int Chip=0; ChipGetNumberOfChips(); Chip++) { GetBoard(i)->GetTime(Chip, Time[Chip], true, false); } // Write calibration data to file if (asprintf(&Filename, "%s/TCalib_%d_%.2fGHz.txt", fCalibDataPath, GetBoard(i)->GetBoardSerialNumber(), DRSFreq[i]) == -1) { PrintMessage("Error: asprintf() failed, cannot generate filename (%s)\n", strerror(errno)); return; } if ((Calibfile=fopen(Filename,"w")) == NULL) { PrintMessage("Error: Could not open file '%s' \n", Filename); } else { if(fprintf(Calibfile, "# DRS time calibration\n") == -1) WriteOK = false; for (int Bin=0; BinGetNumberOfChips(); Chip++) { if(fprintf(Calibfile, "%.2f ", Time[Chip][Bin]) == -1) WriteOK = false; } if(fprintf(Calibfile, "\n") == -1) WriteOK = false; } if (fclose(Calibfile) != 0) PrintMessage("Error closing file '%s'\n", Filename); } if (!WriteOK) PrintMessage("Error writing to file '%s'\n", Filename); else PrintMessage("Calibration written to file '%s'\n", Filename); free(Filename); } PrintMessage("Time calibration finished\n"); } */ // // Print status // void FAD::cmd_status() { // ==== Print board overview ==== if (Parameter.size() == 1) { // Count active board unsigned int Count = 0, Error = 0; for (unsigned int i=0; iActive) Count++; if (Boards[i]->CommError) Error++; } PrintMessage(" Number of FAD boards: %d Boards with communication error: %d Active boards: ", Boards.size(), Error); // Print list of active boards if (Count == 0) PrintMessage("none\n"); else if (Count == Boards.size()) PrintMessage("all\n"); else for (unsigned int i=0; iActive) PrintMessage(" %d", i); } return; } // ==== Print details for given range ==== struct Range R = {0, Boards.size()}; if (!ConvertToRange(Parameter[1], R)) { PrintMessage("Error, out of range.\n"); return; } for (int i=0; i<(int) Boards.size(); i++) { if (i R.Max) continue; struct FADBoard::BoardStatus S = Boards[i]->GetStatus(); PrintMessage("Board #%d (%sactive) Communication %s\n", i, Boards[i]->Active ? "":"in", Boards[i]->CommError ? "ERROR":"OK"); PrintMessage("DAC %d %d %d %d %d %d %d %d\n", S.DAC[0], S.DAC[1], S.DAC[2], S.DAC[3], S.DAC[4], S.DAC[5], S.DAC[6], S.DAC[7] ); PrintMessage("Temperature %.2f %.2f %.2f %.2f", S.Temp[0], S.Temp[1], S.Temp[2], S.Temp[3]); for (unsigned int i=0; iGetBoardSerialNumber(), GetBoard(i)->GetFirmwareVersion(), GetBoard(i)->GetTemperature(), ACalibTemp[i]); if (GetBoard(i)->GetStatusReg() & BIT_RUNNING) PrintMessage(" Domino wave running\n"); if (GetBoard(i)->GetCtrlReg() & BIT_DMODE) PrintMessage(" DMODE circular\n"); else PrintMessage(" DMODE single shot\n"); if (GetBoard(i)->GetCtrlReg() & BIT_ENABLE_TRIGGER1) PrintMessage(" ENABLE_TRIGGER\n"); if (GetBoard(i)->GetCtrlReg() & BIT_ACAL_EN) PrintMessage(" ACAL enabled\n"); PrintMessage(" Trigger bus: 0x%08X\n", GetBoard(i)->GetTriggerBus()); else PrintMessage(" Domino wave stopped\n"); } }*/ } // for() } // // Adress FAD boards // void FAD::cmd_board() { struct Range R = {0, Boards.size()}; int Mode = 0; // Check if given boards should be enabled or disabled if (Parameter[1].size() >= 1) { if (Parameter[1][0] == '+') Mode = 1; if (Parameter[1][0] == '-') Mode = -1; } if (Mode != 0) Parameter[1][0] = ' '; // Evaluate given range if (!ConvertToRange(Parameter[1], R)) { PrintMessage("Error, out of range.\n"); return; } // Enable or disable boards for (int i=0; i<(int) Boards.size(); i++) { if (Mode == 0) Boards[i]->Active = false; if (i >= R.Min && i <= R.Max) { if (Mode != -1) Boards[i]->Active = true; else Boards[i]->Active = false; } } } // // Set DIM event update delay // void FAD::cmd_update() { double Delay; if (Parameter.size()==2 && ConvertToDouble(Parameter[1], &Delay) && Delay>0) EventUpdateDelay = Delay; else PrintUsage(); } // // Print help // void FAD::cmd_help() { char Buffer[MAX_COM_SIZE]; for(unsigned int i=0; i Execute shell command\n\n" "Items in <> are mandatory, in [] optional, | indicates mutual exclusive.\n" "Strings containing spaces have to be enclosed in \"double quotes\".\n" "Ranges can be given as 'all', a single number or in the form 'a-b'.\n"); } // // Cancel current operation // void FAD::cmd_cancel() { if (Mode == idle) PrintMessage("Nothing to cancel\n"); else { PrintMessage("Requested cancelation of current operation\n"); Cancel = true; } } // // Exit programm // SIGTERM sets ExitRequest flag, and also makes readline() return (if command from DimCommand thread) // void FAD::cmd_exit() { pthread_kill(MainThread, SIGTERM); } // ----------------------------- // ***** Other functions ***** // ----------------------------- // // Amplitude calibration (lauched as thread by cmd_acalib()) // void FAD::AmplitudeCalibration() { static unsigned int ReqNum = 10; unsigned short Buffer[2*NChips*NChannels]; unsigned short DACCmd[] = {htons(CMD_Write | (BADDR_DAC + 0)), 0}; /* Procedure 1. Register sampling frequency from FTM! ... 5. Issue single trigger and verify settings ... 11. Secondary calibration */ struct FADBoard::BoardStatus *Status = new struct FADBoard::BoardStatus [Boards.size()]; PrintMessage("Staring amplitude calibration of all active boards/n Note: No input signals must be connected\n"); // Initialise settings for calibration for (unsigned int Brd=0; BrdGetStatus(); // Set all ROI to 1024 for (unsigned int i=0; iSend(Buffer, sizeof(Buffer)); // Set DAC first value DACCmd[1] = htons(10); Boards[Brd]->Send(DACCmd, sizeof(DACCmd)); // Start accumulation Boards[Brd]->AccumulateSum(ReqNum); Boards[Brd]->Send(CMD_Trigger_C); } // Wait until data for all boards taken bool Done = false; while (!Done && !Cancel) { usleep(300000); for (unsigned int Brd=0; BrdActive && Boards[Brd]->DoSum) Done = false; } } for (unsigned int Brd=0; BrdBaseline[i][j][k] = Boards[Brd]->Sum[i][j][k] / 10; } // Set second DAC value DACCmd[1] = htons(30000); Boards[Brd]->Send(DACCmd, sizeof(DACCmd)); // Start accumulation Boards[Brd]->AccumulateSum(ReqNum); } // Wait until data for all boards taken Done = false; while (!Done && !Cancel) { usleep(300000); for (unsigned int Brd=0; BrdActive && Boards[Brd]->DoSum) Done = false; } } // Stop triggering, write back original ROI and DAC settings for (unsigned int Brd=0; BrdSend(CMD_Trigger_S); // Determine gain for (unsigned int i=0; iGain[i][j][k] = (Boards[Brd]->Sum[i][j][k] / 10)/Boards[Brd]->Baseline[i][j][k]; } for (unsigned int i=0; iSend(Buffer, sizeof(Buffer)); DACCmd[1] = htons(Status[Brd].DAC[0]); Boards[Brd]->Send(DACCmd, sizeof(DACCmd)); // Store calibration time and temperature Boards[Brd]->ACalibTime = Cancel ? -1 : time(NULL); Boards[Brd]->ACalibTemp = 0; for (unsigned int i=0; iACalibTemp += Status[Brd].Temp[i] / NTemp; } delete[] Status; PrintMessage("Amplitude calibration of all active boards finished, original ROI and DAC set\n"); Mode = idle; // Write short calibration information /*time_t Time = time(NULL); FILE *InfoFile = fopen(CalibInfoFilename, "w"); if (InfoFile != NULL) { fprintf(InfoFile, "# Calibration information as of %s\n", ctime(&Time)); for (int i=0; iGetBoardSerialNumber(), ACalib[i], ACalibTemp[i], TCalib[i], DRSFreq[i]); } fclose(InfoFile); } else PrintMessage("Could not write calibration information to file '%s'\n", CalibInfoFilename); */ } // Launch read thread inside class void FAD::LaunchAmplitudeCalibration(class FAD *m) { m->AmplitudeCalibration(); } // // DIM event service update thread (publishes M0 format) // void FAD::EventThread() { struct timeval Time; struct timeval LastUpdate; bool Update; struct FADBoard::BoardStatus S; gettimeofday(&LastUpdate, NULL); // Create DIM event data service int EventSize = sizeof(RunHeader)+ Boards.size()*sizeof(BoardStructure)+sizeof(EventHeader) + Boards.size()*(NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int)); char *EventData = new char [EventSize]; DimService *EventService = new DimService (SERVER_NAME"/EventData", (char *) "C", NULL, 0); memset(EventData, 0, EventSize); // Calculate pointers to EventData array RunHeader *RHeader = (RunHeader *) EventData; BoardStructure **BStruct = new BoardStructure * [Boards.size()]; for (unsigned int i=0; iMagicNum = 0xE0E0; RHeader->DataFormat = 1; RHeader->RunHeaderSize = sizeof(RunHeader); RHeader->EventHeaderSize = sizeof(EventHeader); RHeader->BoardStructureSize = sizeof(BoardStructure); RHeader->SoftwareRevision = 0xFFFF; // Update RHeader->Identification = 0; RHeader->Type = 0; // Run type: 0=data, 1=pedestal, 3=test RHeader->Events = 1; RHeader->RunNumber = -1; RHeader->FileNumber = 0; snprintf(RHeader->Description, sizeof(RHeader->Description), "FADctrl_Event"); RHeader->NBoards = Boards.size(); RHeader->NChips = NChips; RHeader->NChannels = NChannels; RHeader->Samples = NBins; // Always full pipeline RHeader->Offset = 0; RHeader->NBytes = 2; // M0 EventHeader EHeader->EventSize = Boards.size()*(NChips*NChannels*NBins*sizeof(short) + NChips*sizeof(int)); // Update loop while (!ExitRequest) { usleep(EventUpdateDelay); // Update run and event header with current time gettimeofday(&Time, NULL); RHeader->StartSecond = Time.tv_sec; RHeader->StartMicrosecond = Time.tv_usec; RHeader->EndSecond = Time.tv_sec; RHeader->EndMicrosecond = Time.tv_usec; EHeader->Second = Time.tv_sec; EHeader->Microsecond = Time.tv_usec; // Check boards for new data since last update Update = false; for (unsigned int Brd=0; BrdGetStatus(); if (S.Update.tv_sec>LastUpdate.tv_sec || ((S.Update.tv_sec==LastUpdate.tv_sec) && (S.Update.tv_sec>LastUpdate.tv_sec))) { Update = true; // Fill M0 BoardStructure BStruct[Brd]->SerialNo = S.BoardID; BStruct[Brd]->NomFreq = 2; BStruct[Brd]->BoardTemp = 0; for (unsigned int i=0; iBoardTemp += S.Temp[i]/NTemp; BStruct[Brd]->ScaleFactor = 1/2.048; // Update event header with ID and Type of current board EHeader->EventNumber = S.TriggerID; EHeader->TriggerType = S.TriggerType; // Write trigger cells for(unsigned int i=0; iLock(); for (unsigned int Chip=0; ChipData[Chip][Chan][i]; Count += NBins - S.ROI[Chip][Chan]; } Boards[Brd]->Unlock(); } } if (Update) { gettimeofday(&LastUpdate, NULL); EventService->updateService(EventData, EventSize); } } // Clean up delete[] BStruct; delete EventService; delete[] EventData; } // Launch event thread inside class void FAD::LaunchEventThread(class FAD *m) { m->EventThread(); } /* // Read calibration data bool FAD::ReadCalibration() { static char Buffer[MAX_COM_SIZE]; int Serial, Calib; float Temp, Freq; for (int i=FirstBoard; i<=LastBoard; i++) { if (GetBoard(i)->GetDRSType() == 4) { if (ACalib[i] == false) { // Check calibration info file if EEPROM data on DRS board still valild FILE *CalibInfo = fopen(CalibInfoFilename, "r"); if (CalibInfo == NULL) return false; fgets(Buffer, sizeof(Buffer), CalibInfo); // skip first two lines fgets(Buffer, sizeof(Buffer), CalibInfo); while (fgets(Buffer, sizeof(Buffer), CalibInfo) != NULL) { if (sscanf(Buffer, "%d %d %f %*d %f", &Serial, &Calib, &Temp, &Freq) != 4) { fclose(CalibInfo); return false; } if (Serial==GetBoard(i)->GetBoardSerialNumber() && int(Freq*100)==int(DRSFreq[i]*100) && Calib==1) { ACalib[i] = true; ACalibTemp[i] = Temp; break; } } fclose(CalibInfo); } } else { if (!ACalib[i]) { GetBoard(i)->SetCalibrationDirectory(fCalibDataPath); PrintMessage("Reading response calibration file for board %d from: \"%s\"\n", i, fCalibDataPath); for (int Chip=0; ChipGetNumberOfChips(); Chip++) { if (GetBoard(i)->GetResponseCalibration()->ReadCalibration(Chip) == false) return false; } ACalib[i] = true; } } if (fabs(ACalibTemp[i]-GetBoard(i)->GetTemperature())>2) PrintMessage("Warning: Large difference to calibration temperature for board %d\n", i); } // Loop over boards return true; } // Set DOMINO mode void FAD::SetDOMINOMode(int mode) { for (int i=FirstBoard; i<=LastBoard; i++) { GetBoard(i)->SetDominoMode(mode==1 ? 1:0); PrintMessage("Domino mode of board %d switched to %s.\n",i,mode==1 ? "continuous":"single shot"); } } // Set DOMINO readout mode void FAD::SetDOMINOReadMode(int mode) { for (int i=FirstBoard; i<=LastBoard; i++) { GetBoard(i)->SetReadoutMode(mode); PrintMessage("Start readout of board %d from %s.\n",i,mode==0 ? "first bin":"stop position"); } } // Set DOMINO wave mode void FAD::SetDOMINOWaveMode(int mode) { for (int i=FirstBoard; i<=LastBoard; i++) { GetBoard(i)->SetDominoActive(mode); PrintMessage("Domino wave of board %d is %s during readout\n",i,mode==1 ? "running":"stopped"); } } */ // // Print usage text for command // void FAD::PrintUsage() { for(unsigned int i=0; i0 && Text[strlen(Text)-1]=='\n') rl_on_new_line(); // New prompt // Send to DIM text service ConsoleOut->updateService(Text); // Free old text if (ConsoleText != Error) free(ConsoleText); ConsoleText = Text; } // // Check if two strings match (min 1 character must match) // bool FAD::Match(string str, const char *cmd) { return strncasecmp(str.c_str(),cmd,strlen(str.c_str())==0 ? 1:strlen(str.c_str())) ? false:true; } // // Conversion function from string to double, int or range // // Return false if conversion did not stop on whitespace or EOL character bool FAD::ConvertToDouble(string String, double *Result) { char *EndPointer; *Result = strtod(String.c_str(), &EndPointer); if(!isspace(*EndPointer) && *EndPointer!='\0') return false; return true; } bool FAD::ConvertToInt(string String, int *Result) { char *EndPointer; *Result = (int) strtol(String.c_str(), &EndPointer, 0); if(!isspace(*EndPointer) && *EndPointer!='\0') return false; return true; } bool FAD::ConvertToRange(string String, struct FAD::Range &R) { int N, M; // Full range if (Match(String, "all")) return true; // Single number if (ConvertToInt(String, &N)) { if (N>= R.Min && N<=R.Max) { R.Max = R.Min = N; return true; } return false; } // Range a-b vector V = EvidenceServer::Tokenize(String, "-"); if (V.size()==2 && ConvertToInt(V[0], &N) && ConvertToInt(V[1], &M) && N>=R.Min && M<=R.Max) { R.Min = N; R.Max = M; return true; } return false; }