/********************************************************************\ 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|enable|disable]", "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, "", "Send arbitrary data to board"}, {"acalib", &FAD::cmd_acalib, true, 0, "[n|invalidate|file]", "Perform or read amplitude calibration (n events)"}, //{"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"}, {"socketmode", &FAD::cmd_socketmode, true, 1, "", "Choose which Sockets are used for data transmission"}, {"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()); // DIM console service used in PrintMessage() ConsoleOut = new DimService(SERVER_NAME"/ConsoleOut", (char *) ""); // Construct boards BoardList = Tokenize(GetConfig("BoardList","129.217.160.119")); BoardList = Tokenize("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; // Wait for DIM service thread to quit if (pthread_equal(Thread, pthread_self()) == 0) { if ((Ret = pthread_join(Thread, NULL)) != 0) Message(ERROR, "pthread_join() failed in ~FAD() (%s)", strerror(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 which sockets are used to send data away // case parameter is: "com" - command mode is enabled. // thus only socket 0 is used // case parameter is: "daq" - daq mode is enabled // thus only sockets 1 - 7 are used. // // note: socket 0 is always used to issue commands // void FAD::cmd_socketmode() { for (unsigned int i=0; iSend(CMD_Stop); else if (Match(Parameter[1],"daq")) Boards[i]->Send(CMD_Start); } if (Match(Parameter[1],"com")) PrintMessage("all active boards switched to command mode - socket 0\n"); else if (Match(Parameter[1],"daq")) PrintMessage("all active boards switched to DAQ mode - socket 1..7\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 if (Match(Parameter[1],"enable")) Boards[i]->Send(CMD_TRIGGERS_ON); else if (Match(Parameter[1],"disable")) Boards[i]->Send(CMD_TRIGGERS_OFF); else { PrintUsage(); break; } } if (Match(Parameter[1],"enable")) PrintMessage("all active boards accept now incoming triggers\n"); else if (Match(Parameter[1],"disable")) PrintMessage("no active board accepts any incoming trigger anymore.\n"); // else PrintUsage(); } // // 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, Count; FILE *File; vector Items; // Invalidate calibration? if (Parameter.size() == 2 && Match(Parameter[1], "invalidate")) { for (unsigned int i=0; iACalibTime = -1; return; } // Read calibration data from file? if (Parameter.size() == 2 && !ConvertToInt(Parameter[1], &NumCalibEvents)) { // Open file if ((File = fopen(Parameter[1].c_str(), "r")) == NULL) { PrintMessage("Error opening file '%s'\n", Parameter[1].c_str()); return; } PrintMessage("Reading amplitude calibration information from file '%s'\n", Parameter[1].c_str()); // Read file into buffer and close file string Buffer; while (feof(File)==0 && ferror(File)==0) Buffer.push_back((char) fgetc(File)); if (Buffer.size() > 0) Buffer = Buffer.substr(0, Buffer.size()-1); if (fclose(File) != 0) PrintMessage("Could not close file '%s'\n", Parameter[1].c_str()); // Search for calibration data for boards vector Result = Tokenize(Buffer, "\n"); for (unsigned int Brd=0; BrdName) == string::npos) continue; PrintMessage("Found calibration data for board '%s'\n", Boards[Brd]->Name); Items = Tokenize(Result[Line]); // Check if correct number of items if (Items.size() != NChips*NChannels*NBins*2 + 3) { PrintMessage("Error, data format invalid\n", Parameter[1].c_str()); return; } // Extract data Boards[Brd]->ACalibTemp = atof(Items[1].c_str()); Boards[Brd]->ACalibTime = atoi(Items[2].c_str()); Count = 3; for (unsigned int i=0; iBaseline[i][j][k] = atoi(Items[Count++].c_str()); Boards[Brd]->Gain[i][j][k] = atof(Items[Count++].c_str()); } } } } } // Loop over boards return; } // Reading calibration from file // Set number of events required for calibration if (Parameter.size()==1 || !ConvertToInt(Parameter[1], &NumCalibEvents) || NumCalibEvents<=0) { NumCalibEvents = DEFAULT_NUM_CALIB_EVENTS; } // Set mode before launching 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)); } } // // 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 - %s (%sactive) Communication %s\n", i, Boards[i]->Name, 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_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; 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() { vector Status; vector ROICmd; unsigned short DACCmd[] = {htons(CMD_Write | (BADDR_DAC + 1)), 0, htons(CMD_Write | (BADDR_DAC + 2)), 0, htons(CMD_Write | (BADDR_DAC + 3)), 0}; /* Procedure 5. Issue single trigger and verify settings ... 11. Secondary calibration */ PrintMessage("Staring amplitude calibration of all active boards (%d events)\n" " Note: No input signals must be connected\n", NumCalibEvents); // Prepare command to set all ROIs to 1024 for (unsigned int i=0; iACalibTime = -1; // Save initial board status Status.push_back(Boards[Brd]->GetStatus()); // Disarm first, in order to change ROI & DAC settings //Boards[Brd]->Send(CMD_TRIGGERS_OFF); // Set all ROI to 1024 Boards[Brd]->Send(&ROICmd[0], ROICmd.size()*sizeof(unsigned short)); // Set first DAC value DACCmd[1] = htons(0); DACCmd[3] = htons(0); DACCmd[5] = htons(0); Boards[Brd]->Send(DACCmd, sizeof(DACCmd)); // Switch off SCLK //Boards[Brd]->Send(CMD_SCLK_OFF); // Arm again, in order to take data //Boards[Brd]->Send(CMD_TRIGGERS_ON); // Start accumulation Boards[Brd]->AccumulateSum(NumCalibEvents); } // 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] / NumCalibEvents; } } // Switch on SCLK Boards[Brd]->Send(CMD_SCLK_ON); // Disarm first, in order to change ROI & DAC settings //Boards[Brd]->Send(CMD_TRIGGERS_OFF); // Set second DAC value DACCmd[1] = htons(50000); DACCmd[3] = htons(50000); DACCmd[5] = htons(50000); Boards[Brd]->Send(DACCmd, sizeof(DACCmd)); // Switch off SCLK //Boards[Brd]->Send(CMD_SCLK_OFF); // Arm again //Boards[Brd]->Send(CMD_TRIGGERS_ON); // Start accumulation Boards[Brd]->AccumulateSum(NumCalibEvents); } // 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_SCLK_ON); // Determine gain for (unsigned int i=0; iGain[i][j][k] = (Boards[Brd]->Sum[i][j][k] / NumCalibEvents)-Boards[Brd]->Baseline[i][j][k]; } } ROICmd.clear(); for (unsigned int i=0; iSend(&ROICmd[0], ROICmd.size()*sizeof(unsigned short)); DACCmd[1] = htons(Status[Brd].DAC[1]); DACCmd[3] = htons(Status[Brd].DAC[2]); DACCmd[5] = htons(Status[Brd].DAC[3]); 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; } Mode = idle; if (Cancel) { PrintMessage("Amplitude calibration cancelled\n"); return; } PrintMessage("Amplitude calibration of all active boards finished, original ROI and DAC set\n"); // Write calibration data to file time_t Time = time(NULL); struct tm *TimeInfo; char Buffer[200]; // Generate filename TimeInfo = localtime(&Time); if (strftime(Buffer, sizeof(Buffer), "/FADcalib_%y-%m-%jT%X.txt", TimeInfo) == 0) { PrintMessage("Could not generate calibration data file name, strftime() failed\n"); return; } string Filename = string(getenv("HOME"))+Buffer; FILE *File = fopen(Filename.c_str(), "w"); if (File == NULL) { PrintMessage("Could not open calibration data file '%s'\n", Filename.c_str()); return; } // Fix: Should actually contain serial number! for (unsigned int Brd=0; BrdName, Boards[Brd]->ACalibTemp, (int) Boards[Brd]->ACalibTime); for (unsigned int i=0; iBaseline[i][j][k], Boards[Brd]->Gain[i][j][k]); } } } } // Close file if (fclose(File) != 0) { PrintMessage("Could not close calibration file '%s'\n", Filename.c_str()); } PrintMessage("Wrote amplitude calibration information to file '%s'\n", Filename.c_str()); } // 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; double Temp; 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*1e6); // 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_usec>LastUpdate.tv_usec))) { 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; ChipACalibTime == -1) Data[Count++] = Boards[Brd]->Data[Chip][Chan][i]; else { Temp = (Boards[Brd]->Data[Chip][Chan][i] - Boards[Brd]->Baseline[Chip][Chan][(i+S.TriggerCell[Chip])%NBins]); Temp *= Boards[Brd]->Gain[Chip][Chan][0]/Boards[Brd]->Gain[Chip][Chan][(i+S.TriggerCell[Chip])%NBins]; Data[Count++] = (short) Temp; } } 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(); } /* // 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; }