Changeset 211
- Timestamp:
- 05/21/10 13:31:27 (14 years ago)
- Location:
- drsdaq
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
drsdaq/DAQReadout.cc
r193 r211 34 34 {"take", &DAQReadout::cmd_take, false, "<d|p|t> [n] [source]", "Start run (data, pedestal or test) with n events"}, 35 35 {"events", &DAQReadout::cmd_events, false, "", "Number of events in current run"}, 36 {"start", &DAQReadout::cmd_ start, true, "", "Start DRS and DAQ without disk writing (feedback will be called)"},36 {"start", &DAQReadout::cmd_take, false, "", "Start run without disk writing"}, 37 37 {"stop", &DAQReadout::cmd_stop, false, "", "Issue soft trigger and stop DAQ"}, 38 38 {"regtest", &DAQReadout::cmd_regtest, true, "", "DRS register test"}, … … 45 45 {"disk", &DAQReadout::cmd_disk, false, "" ,"Remaining disk space"}, 46 46 {"uptime", &DAQReadout::cmd_uptime, false, "", "Get DAQ uptime"}, 47 {"update", &DAQReadout::cmd_update, false, "<sec>", "Minimum delay between updates to DIM event service"}, 47 48 {"exit", &DAQReadout::cmd_exit, false, "", "Exit program"}, 48 49 {"fmode", &DAQReadout::cmd_fmode, false, "[off|active|targ]", "Set or get feedback mode"}, … … 55 56 56 57 58 // Global pointer for thread entry routines 59 class DAQReadout *This; 60 57 61 // ----------------------------------------------- 58 62 // ***** Constructor: Class initialisation ***** … … 60 64 // 61 65 62 DAQReadout::DAQReadout() :EvidenceServer(SERVER_NAME) { 63 64 time(&StartTime); // Start time of DAQ 66 DAQReadout::DAQReadout(): 67 DimCommand((char *) SERVER_NAME"/Command", (char *) "C"), 68 EvidenceServer(SERVER_NAME) { 69 70 // Global class pointer 71 This = this; 72 MainThread = getpid(); 73 74 // Start time of DAQ 75 time(&StartTime); 76 77 // Initialize mutex for thread synchronisation 78 if (pthread_mutex_init(&Mutex, NULL) != 0) { 79 State(FATAL, "pthread_mutex_init() failed"); 80 } 65 81 66 82 // Initialize status structure 67 daq_state = stopped; 68 daq_runtype = data; 69 Socket = -1; 70 Exit = false; 71 NumEvents = 0; 72 NumEventsRequested = 0; 73 NumBoards = 0; 74 FirstBoard = 0; 75 LastBoard = -1; 76 CmdFromSocket = false; 83 daq_state = stopped; 84 daq_runtype = data; 85 NumEvents = 0; 86 NumEventsRequested = 0; 87 NumBoards = 0; 88 FirstBoard = 0; 89 LastBoard = -1; 90 MinDelay = 1; 77 91 78 92 // Get configuration data … … 83 97 fMinDiskSpaceMB = atoi(GetConfig("MinDiskSpaceMB")); 84 98 fMaxFileSizeMB = atoi(GetConfig("MaxFileSizeMB")); 85 fCCPort = atoi(GetConfig("CCPort"));86 99 fDefaultFrequency = atof(GetConfig("DefaultFrequency")); 87 100 … … 106 119 TCalib = new bool [NumBoards]; 107 120 108 if (NumBoards == 0) PrintMessage("No DRS boards found - check VME crate and configuration file!\n");121 if (NumBoards == 0) PrintMessage("No DRS boards found\n"); 109 122 110 123 for (int i=0; i<NumBoards; i++) { … … 121 134 WaveForm = new short [NumBoards == 0 ? 1:NumBoards][kNumberOfChipsMax][kNumberOfChannelsMax][kNumberOfBins]; 122 135 TriggerCell = new int [NumBoards == 0 ? 1:NumBoards][kNumberOfChipsMax] (); // Zero initialised 123 124 // Create instance of HV feedback (must be called after CMC board detection) 136 137 DIMEventData = new char [sizeof(RunHeader) + sizeof(EventHeader) + 138 sizeof(BoardStructure)*(NumBoards == 0 ? 1:NumBoards) + 139 sizeof(int)*(NumBoards == 0 ? 1:NumBoards)*kNumberOfChipsMax + 140 sizeof(short)*(NumBoards == 0 ? 1:NumBoards)*kNumberOfChipsMax*kNumberOfChannelsMax*kNumberOfBins]; 141 142 // Create DIM event data service 143 EventService = new DimService (SERVER_NAME"/EventData", (char *) "C", DIMEventData, 0); 144 145 // Create instance of HV feedback (must be called after board detection) 125 146 HVFB = new HVFeedback(this); 126 147 } … … 132 153 DAQReadout::~DAQReadout() { 133 154 134 delete RHeader; delete EHeader; 135 delete HVFB; delete[] ACalibTemp; 136 delete[] ACalib; delete[] TCalib; 137 delete[] DRSFreq; delete[] BStruct; 138 delete[] WaveForm; delete[] TriggerCell; 155 delete EventService; 156 delete[] DIMEventData; 157 delete RHeader; delete EHeader; 158 delete HVFB; delete[] ACalibTemp; 159 delete[] ACalib; delete[] TCalib; 160 delete[] DRSFreq; delete[] BStruct; 161 delete[] WaveForm; delete[] TriggerCell; 162 163 // Destroy mutex 164 if (pthread_mutex_destroy(&Mutex) != 0) State(ERROR, "pthread_mutex_destroy() failed"); 139 165 } 140 166 … … 143 169 // -------------------------------- 144 170 145 void DAQReadout:: CommandControl(char *Command) {171 void DAQReadout::Execute(char *Command) { 146 172 147 173 if (strlen(Command)==0) return; // Ignore empty commands … … 158 184 if (Match(Param[0], CommandList[CmdNumber].Name)) { 159 185 if(CommandList[CmdNumber].NeedNotBusy && daq_state==active) PrintMessage("DAQ is busy\n"); 160 else if(CommandList[CmdNumber].NeedNotBusy && NumBoards==0) PrintMessage("No mezzanine boards available\n"); 161 else (this->*CommandList[CmdNumber].CommandPointer)(); 186 else if(CommandList[CmdNumber].NeedNotBusy && NumBoards==0) PrintMessage("No boards available\n"); 187 else { 188 pthread_mutex_lock(&Mutex); 189 (this->*CommandList[CmdNumber].CommandPointer)(); 190 pthread_mutex_unlock(&Mutex); 191 } 162 192 return; 163 193 } 164 194 PrintMessage("Unknown command '%s'\n",Param[0]); 165 return;166 195 } 167 196 … … 186 215 // Print DAQ configuration 187 216 void DAQReadout::cmd_config() { 188 PrintConfig( CmdFromSocket ? MsgToSocket :MsgToConsole);217 PrintConfig(MsgToConsole); 189 218 } 190 219 … … 202 231 for (int i=FirstBoard; i<=LastBoard-1; i++) { 203 232 if ((GetBoard(i)->GetNumberOfChannels() != GetBoard(i+1)->GetNumberOfChannels()) || (GetBoard(i)->GetNumberOfChips() != GetBoard(i+1)->GetNumberOfChips())) { 204 PrintMessage("Cannot take data i snot all boards have the same number of DRS chips and channels due to data format restriction\n");233 PrintMessage("Cannot take data if not all boards have the same number of DRS chips and channels due to data format restriction\n"); 205 234 return; 206 235 } … … 241 270 else snprintf(RHeader->Description,sizeof(RHeader->Description),"DUMMY"); 242 271 243 // Request new run number 244 DimRpcInfo RunNumRPC((char *) "NextRunNumber", -1); 245 RunNumRPC.setData((char *) ""); 246 RunNumber = RunNumRPC.getInt(); 247 if(RunNumber < 1) { 248 PrintMessage("Error: No connection to run number dispatcher or received number smaller than 1\n"); 249 return; 250 } 272 // Request new run number (if command was 'start', set run number to -1 --> no disk writing) 273 if (Match(Param[0], "take")) { 274 DimRpcInfo RunNumRPC((char *) "NextRunNumber", -1); 275 276 RunNumRPC.setData((char *) "");printf("and least here\n"); 277 278 RunNumber = RunNumRPC.getInt(); 279 if(RunNumber < 1) { 280 PrintMessage("Error: No connection to run number dispatcher or received number smaller than 1\n"); 281 return; 282 } 283 } 284 else RunNumber = -1; 251 285 252 286 // Create DAQ thread 253 if ((pthread_create(&thread_DAQ, NULL, (void * (*)(void *)) DAQ,(void *) this)) != 0) 254 PrintMessage("pthread_create failed with DAQ thread (%s)\n",strerror(errno)); 287 pthread_t Thread; 288 int Code; 289 if ((Code = pthread_create(&Thread, NULL, (void * (*)(void *)) ::DAQ,(void *) this)) != 0) { 290 PrintMessage("pthread_create() failed with DAQ thread (error code %d)\n", Code); 291 } 255 292 else { 256 293 daq_state = active; 257 294 Stop = false; 258 pthread_detach(thread_DAQ); 295 if ((Code = pthread_detach(Thread)) != 0) { 296 PrintMessage("pthread_detach() failed with DAQ thread (error code %d)\n", Code); 297 } 259 298 } 260 299 } 261 300 262 // Start DRS263 void DAQReadout::cmd_start() {264 if (IsDRSFreqSet()) {265 StartDRS();266 PrintMessage("Domino wave started\n");267 268 // Create DAQ thread269 if ((pthread_create(&thread_DAQ_Silent, NULL, (void * (*)(void *)) DAQ_Silent,(void *) this)) != 0)270 PrintMessage("pthread_create failed with DAQ_Silent thread (%s)\n",strerror(errno));271 else {272 daq_state = active;273 Stop = false;274 pthread_detach(thread_DAQ_Silent);275 }276 }277 }278 279 301 // EEPROM test 280 302 void DAQReadout::cmd_eepromtest() { … … 366 388 } 367 389 368 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole|MsgToLog, "==START== %d %.2f %.2f ",kNumberOfBins+2,DRSFreq[Board],GetBoard(Board)->GetPrecision()); 369 double mean=0,square=0.0; 390 PrintMessage(MsgToConsole, "==START== %d %.2f %.2f ",kNumberOfBins+2,DRSFreq[Board],GetBoard(Board)->GetPrecision()); 370 391 for (int k=0; k<kNumberOfBins; k++) { 371 // PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole|MsgToLog, "%.1f ", (float) WaveForm[Board][Chip][Channel][(k+TriggerCell[Board][Chip])%kNumberOfBins]); 372 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole|MsgToLog, "%.1f ", (float) WaveForm[Board][Chip][Channel][k]); 373 374 mean += (float) WaveForm[atoi(Param[1])][atoi(Param[2])][atoi(Param[3])][(k+TriggerCell[atoi(Param[1])][atoi(Param[2])])%kNumberOfBins]; 375 square += pow((float) WaveForm[atoi(Param[1])][atoi(Param[2])][atoi(Param[3])][(k+TriggerCell[atoi(Param[1])][atoi(Param[2])])%kNumberOfBins],2); 376 377 378 } 379 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole|MsgToLog, "==END=="); 380 PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole|MsgToLog, "\n"); 392 PrintMessage(MsgToConsole, "%.1f ", (float) WaveForm[Board][Chip][Channel][k]); 393 } 394 PrintMessage(MsgToConsole, "==END=="); 395 PrintMessage(MsgToConsole, "\n"); 381 396 PrintMessage(MsgToConsole, "Trigger cell: %d\n", TriggerCell[Board][Chip]); 382 printf("rms: %f\n",sqrt(square/kNumberOfBins - pow(mean/kNumberOfBins,2)));383 397 } 384 398 … … 614 628 " Storage directory: %s\n" 615 629 " Disk space: %lu MByte\n" 616 " Socket state: %s\n"617 630 " Total number of DRS boards: %d\n" 618 631 " Active DRS boards: %d\n", … … 620 633 daq_state==active ? daq_runtype_str[daq_runtype]:"n/a", NumEvents, 621 634 NumEventsRequested, fRawDataPath, 622 CheckDisk(fRawDataPath), Socket==-1 ? "disconnected":"connected", 623 NumBoards, LastBoard - FirstBoard + 1); 635 CheckDisk(fRawDataPath), NumBoards, LastBoard - FirstBoard + 1); 624 636 625 637 for (int i=FirstBoard;i<=LastBoard;i++) … … 705 717 } 706 718 707 // Print help (only to console or socket, not to log file) 719 // Set input range 720 void DAQReadout::cmd_update() { 721 722 if (NParam != 2 || atoi(Param[1]) < 0) { 723 PrintUsage(); 724 return; 725 } 726 MinDelay = atoi(Param[1]); 727 } 728 729 // Print help 708 730 void DAQReadout::cmd_help() { 731 709 732 char Buffer[MAX_COM_SIZE]; 733 710 734 for(unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) { 711 735 snprintf(Buffer, sizeof(Buffer), "%s %s", CommandList[i].Name, CommandList[i].Parameters); 712 PrintMessage( CmdFromSocket ? MsgToSocket:MsgToConsole,"%-28s%s\n", Buffer, CommandList[i].Help);736 PrintMessage(MsgToConsole, "%-28s%s\n", Buffer, CommandList[i].Help); 713 737 } 714 PrintMessage( CmdFromSocket ? MsgToSocket:MsgToConsole,".<command> Execute shell command\n\n"738 PrintMessage(MsgToConsole,".<command> Execute shell command\n\n" 715 739 "Items in <> are mandatory, in [] optional, | indicates mutual exclusive or.\n" 716 740 "Test data can also be written if no DRS boards are available.\n" … … 718 742 } 719 743 720 // Exit programm 744 // Exit programm - SIGTERM sets ExitRequest flag 745 // If command comes from DimCommand thread, SIGTERM also makes readline() return 721 746 void DAQReadout::cmd_exit() { 722 if (CmdFromSocket) { 723 PrintMessage("Exit command not allowed over socket.\n"); 724 return; 725 } 726 if (daq_state==active) PrintMessage("Issue \"stop\" first to stop daq\n"); 727 else { 728 Exit = true; 729 if(SocketThread != NULL) pthread_kill(*SocketThread, SIGUSR1); 730 } 747 748 if (daq_state == active) PrintMessage("Issue 'stop' first to stop daq\n"); 749 else kill(MainThread, SIGTERM); 731 750 } 732 751 733 752 // Set/get mode of feedback 734 753 void DAQReadout::cmd_fmode() { 754 735 755 if(Match(Param[1],"off")) HVFB->SetFBMode(FB_Off); 736 756 if(Match(Param[1],"active")) HVFB->SetFBMode(FB_Active); … … 741 761 // Set/get current number of events 742 762 void DAQReadout::cmd_faverage() { 763 743 764 if(NParam==1) PrintMessage("Current number of feedback events: %u (acting when %u events are reached)\n", 744 765 HVFB->GetCurrentCount(), HVFB->GetNumAverages()); … … 749 770 // Set/get feedback gain 750 771 void DAQReadout::cmd_fgain() { 772 751 773 if(NParam==2) HVFB->SetGain(atof(Param[1])); 752 774 PrintMessage("Feedback gain is %.2f\n", HVFB->GetGain()); … … 755 777 // Set/get target value 756 778 void DAQReadout::cmd_ftarget() { 779 757 780 if(NParam==1) HVFB->GetTargets(); 758 781 else if(NParam!=5) PrintUsage(); … … 768 791 // Start response measurement 769 792 void DAQReadout::cmd_fresponse() { 793 770 794 if(NParam==1) HVFB->GetResponse(); 771 795 else if(atof(Param[1])) HVFB->MeasureResponse(atof(Param[1])); … … 775 799 // Print feedback configuration 776 800 void DAQReadout::cmd_fconfig() { 777 HVFB->PrintConfig(CmdFromSocket ? MsgToSocket : MsgToConsole); 801 802 HVFB->PrintConfig(MsgToConsole); 778 803 } 779 804 … … 940 965 } 941 966 942 // Open new raw data file 967 // Open new raw data file (if RunNumber == -1, data will be written to /dev/null) 943 968 bool DAQReadout::OpenRawFile() { 944 969 … … 955 980 956 981 // Create direcory if not existing (ignore error if already existing) and change to it 957 snprintf(Buffer, sizeof(Buffer), "%s/%s", fRawDataPath, RunDate); 958 if(mkdir(Buffer, S_IRWXU|S_IRWXG)==-1 && errno!=EEXIST) { 959 PrintMessage("\rError: Could not create direcory \"%s\" (%s)\n", Buffer, strerror(errno)); 960 return false; 982 if (RunNumber != -1) { 983 snprintf(Buffer, sizeof(Buffer), "%s/%s", fRawDataPath, RunDate); 984 if(mkdir(Buffer, S_IRWXU|S_IRWXG)==-1 && errno!=EEXIST) { 985 PrintMessage("\rError: Could not create direcory \"%s\" (%s)\n", Buffer, strerror(errno)); 986 return false; 987 } 961 988 } 962 989 963 990 // Generate filename 964 snprintf(FileName,sizeof(FileName),"%s/%s/%s_D1_%.8u.%.3u_%c_%s.raw", fRawDataPath, RunDate, 965 RunDate,RunNumber,FileNumber,toupper(daq_runtype_str[daq_runtype][0]),RHeader->Description); 991 if (RunNumber == -1) snprintf(FileName, sizeof(FileName), "/dev/null"); 992 else snprintf(FileName, sizeof(FileName),"%s/%s/%s_D1_%.8u.%.3u_%c_%s.raw", fRawDataPath, RunDate, 993 RunDate, RunNumber, FileNumber, toupper(daq_runtype_str[daq_runtype][0]), RHeader->Description); 966 994 967 995 // Open file with rwx right for owner and group, never overwrite file 968 Rawfile = open(FileName,O_WRONLY|O_CREAT| O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);996 Rawfile = open(FileName,O_WRONLY|O_CREAT|(RunNumber==-1?0:O_EXCL), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); 969 997 if(Rawfile==-1) { 970 998 PrintMessage("\rError: Could not open file \"%s\" (%s)\n", FileName, strerror(errno)); … … 1072 1100 return false; 1073 1101 } 1074 1075 // Event data (It is required that at least three chunks can be written with writev(), therefore 1076 // IOV_MAX>=3 is checked at startup 1077 1102 1078 1103 unsigned int Start, Count = 0; 1079 1104 ssize_t WriteResult, Size = 0; 1080 1105 struct iovec DataPart[IOV_MAX]; 1081 1106 1107 // Write trigger cells 1108 for (int i=FirstBoard; (i<=LastBoard + (NumBoards==0)); i++) { 1109 for (unsigned int k=0; k<RHeader->NChips; k++) { 1110 if ((WriteResult=write(Rawfile, &TriggerCell[i][k], sizeof(int))) != sizeof(int)) { 1111 if (WriteResult == -1) PrintMessage("Error: Could not write trigger cells, terminating run (%s)\n", strerror(errno)); 1112 else PrintMessage("Error: Could only write %u out of %u bytes of event data, terminating run\n", WriteResult, sizeof(int)); 1113 return false; 1114 } 1115 } 1116 } 1117 1118 // Event data (It is required that at least three chunks can be written with writev(), therefore 1119 // IOV_MAX>=3 is checked at startup 1120 1121 1082 1122 // First chunk: trigger cells 1083 DataPart[Count].iov_base = (char *) TriggerCell + FirstBoard*RHeader->NChips*sizeof(int); // TriggerCell is without cast a pointer to an 8-byte unit (two ints) !1084 DataPart[Count++].iov_len = RHeader->NBoards * RHeader->NChips * sizeof(int);1085 Size += DataPart[Count-1].iov_len;1123 //DataPart[Count].iov_base = (char *) TriggerCell + FirstBoard*RHeader->NChips*sizeof(int); // TriggerCell is without cast a pointer to an 8-byte unit (two ints) ! 1124 //DataPart[Count++].iov_len = RHeader->NBoards * RHeader->NChips * sizeof(int); 1125 //Size += DataPart[Count-1].iov_len; 1086 1126 1087 1127 // Remaining chunks: ADC data (two chucks per channel if wrap around of pipeline occurred) … … 1123 1163 PrintMessage(Target, "RawDataPath: %s\n" 1124 1164 "DefaultFrequency: %.2f\tFirstSample: %d\tSamples: %u\n" 1125 "MinDiskSpaceMB: %u\tMaxFileSizeMB: %d\ tCCPort: %d\n"1165 "MinDiskSpaceMB: %u\tMaxFileSizeMB: %d\n" 1126 1166 "CalibDataPath: %s\n", 1127 1167 fRawDataPath,fDefaultFrequency,fFirstSample,fSamples,fMinDiskSpaceMB, 1128 fMaxFileSizeMB,fC CPort,fCalibDataPath);1168 fMaxFileSizeMB,fCalibDataPath); 1129 1169 } 1130 1170 … … 1149 1189 } 1150 1190 1151 // Print message to log file, and screen or socket (depending on command origin)1191 // Print message to console only 1152 1192 void DAQReadout::PrintMessage(const char *Format, ...) { 1153 1193 va_list ArgumentPointer; 1154 1194 va_start(ArgumentPointer, Format); 1155 if(CmdFromSocket) DoPrintMessage(Format, ArgumentPointer, MsgToSocket); 1156 else DoPrintMessage(Format, ArgumentPointer, MsgToConsole); 1195 DoPrintMessage(Format, ArgumentPointer, MsgToConsole); 1157 1196 va_end(ArgumentPointer); 1158 1197 } … … 1163 1202 void DAQReadout::DoPrintMessage(const char *Format, va_list ArgumentPointer, int Target) { 1164 1203 1165 static char Textbuffer[MAX_COM_SIZE]; // static: it is only allocated once1166 1204 static char Textbuffer[MAX_COM_SIZE]; 1205 1167 1206 memset(Textbuffer, 0, sizeof(Textbuffer)); 1168 1207 vsnprintf(Textbuffer, sizeof(Textbuffer), Format, ArgumentPointer); … … 1176 1215 fflush(stdout); 1177 1216 } 1217 1218 // Send to DIM service 1219 SetStdOut(Textbuffer); 1220 1178 1221 // Send to log 1179 1222 if(Target & MsgToLog) { … … 1185 1228 else DimClient::sendCommandNB("DColl/Log", SERVER_NAME" asprintf() failed"); 1186 1229 } 1187 // Print to socket 1188 if((Target & MsgToSocket) && Socket!=-1) write(Socket, Textbuffer, strlen(Textbuffer)); 1189 } 1190 1230 } 1231 1232 // DIM command handler (must be non-blocking, otherwise a DIM rpc would dead-lock) 1233 void DAQReadout::commandHandler() { 1234 1235 // Copy command to new buffer (must be freed by the new thread) 1236 char *Command; 1237 if (asprintf(&Command, "%s", getString()) == -1) { 1238 PrintMessage("asprintf() failed in DRSReadout::commandHandler() (%s)\n", strerror(errno)); 1239 return; 1240 } 1241 1242 // Create detached command handling thread 1243 pthread_t Thread; 1244 int Code; 1245 if ((Code = pthread_create(&Thread, NULL, (void * (*)(void *)) ::Execute,(void *) Command)) != 0) { 1246 PrintMessage("pthread_create() failed in DRSReadout::commandHandler() (%s)\n", strerror(Code)); 1247 } 1248 else { 1249 if ((Code = pthread_detach(Thread)) != 0) { 1250 PrintMessage("pthread_detach() failed in DRSReadout::commandHandler() (%s)\n", strerror(Code)); 1251 } 1252 } 1253 } 1254 1255 /********************************************************************\ 1256 1257 DAQ Thread 1258 1259 This thread takes data until the requested number of events is reached, 1260 until no more disk space is available or until data taking is stopped. 1261 No mutex mechanism is used since variables will never be written 1262 simultaneoously by this and the main thread. 1263 1264 \********************************************************************/ 1265 1266 void DAQReadout::DAQ() { 1267 1268 struct timeval StartTime, StopTime; 1269 unsigned int EventsInFile; 1270 unsigned long long RunSize = 0; 1271 bool WriteError = false; 1272 time_t LastDIMUpdate = 0; 1273 off_t FileSize; 1274 int DIMSize; 1275 1276 NumEvents = 0; 1277 FileNumber = 0; 1278 HVFB->ClearAverages(); 1279 gettimeofday(&StartTime, NULL); 1280 PrintMessage("\rStarting run #%d (%s) with %u event(s)\n", RunNumber, daq_runtype_str[daq_runtype], NumEventsRequested); 1281 1282 do { 1283 // Check if enough disk space is left 1284 if (CheckDisk(fRawDataPath) <= fMinDiskSpaceMB+fMaxFileSizeMB) { 1285 PrintMessage("\rError: Disk space after next file (max. %d MByte) below %d MByte\n", fMaxFileSizeMB, fMinDiskSpaceMB); 1286 break; 1287 } 1288 1289 // Init run header, open raw file, write run header 1290 if (!OpenRawFile()) break; 1291 PrintMessage("\rData file \"%s\" opened.\n", FileName); 1292 EventsInFile = 0; 1293 FileSize = 0; 1294 1295 WriteError |= !WriteRunHeader(); 1296 StartDRS(); 1297 1298 // Copy run header and board structures to buffer for DIM event service 1299 memcpy(DIMEventData, RHeader, sizeof(RunHeader)); 1300 ((RunHeader *) DIMEventData)->Events = 1; // always contains 1 event 1301 memcpy(DIMEventData+sizeof(RunHeader), &BStruct[FirstBoard], sizeof(BoardStructure)*(LastBoard-FirstBoard+1+(NumBoards==0))); 1302 1303 // Service size for DIM 1304 DIMSize = sizeof(RunHeader) + sizeof(EventHeader) + 1305 sizeof(BoardStructure)*RHeader->NBoards + 1306 sizeof(int)*RHeader->NBoards*RHeader->NChips + 1307 sizeof(short)*RHeader->NBoards*RHeader->NChips*RHeader->NChannels*RHeader->Samples; 1308 1309 // Take data until finished, stopped or file too large 1310 while ((NumEvents<NumEventsRequested || NumEventsRequested==0) && 1311 !Stop && FileSize/1024/1024<fMaxFileSizeMB && !WriteError) { 1312 1313 if (daq_runtype == data) while (IsDRSBusy()); // Wait for hardware trigger (if DAQ stopped, DRS will not be busy anymore) 1314 else if (daq_runtype == pedestal) StopDRS(); // ..or for software trigger 1315 1316 // Read event data 1317 ReadCalibratedDRSData(); 1318 1319 // Restart here reduces dead-time (already waiting for next trigger while writing) 1320 StartDRS(); 1321 1322 // Write event to disk and update file size 1323 EventsInFile++; 1324 NumEvents++; 1325 WriteError |= !WriteEvent(); 1326 1327 if((FileSize = lseek(Rawfile, 0, SEEK_CUR)) == -1) { 1328 PrintMessage("Error: Could not determine file size, terminating run (%s)\n", strerror(errno)); 1329 WriteError = true; 1330 } 1331 1332 // Call feedback to process event 1333 HVFB->ProcessEvent(); 1334 1335 // Call routine to update DIM service (update rate is limited) 1336 if (time(NULL) - LastDIMUpdate < MinDelay) continue; 1337 LastDIMUpdate = time(NULL); 1338 1339 // Copy new event header 1340 char *Pnt = DIMEventData+sizeof(RunHeader)+RHeader->NBoards*sizeof(BoardStructure); 1341 memcpy(Pnt, EHeader, sizeof(EventHeader)); 1342 Pnt += sizeof(EventHeader); 1343 1344 // Copy new trigger cells 1345 for (int i=FirstBoard; (i<=LastBoard + (NumBoards==0)); i++) { 1346 for (unsigned int k=0; k<RHeader->NChips; k++) { 1347 *((int *) Pnt) = TriggerCell[i][k]; 1348 Pnt += sizeof(int); 1349 } 1350 } 1351 1352 // Copy event data 1353 unsigned int Start; 1354 for (int i=FirstBoard; (i<=LastBoard + (NumBoards==0)); i++) { 1355 for (unsigned int k=0; k<RHeader->NChips; k++) { 1356 // Start bin 1357 if (GetBoard(i)->GetDRSType() == 4) Start = 0; 1358 else Start = (TriggerCell[i][k]-fFirstSample+kNumberOfBins) % kNumberOfBins; 1359 1360 for (unsigned int l=0; l<RHeader->NChannels; l++) { 1361 memcpy(Pnt, &WaveForm[i][k][l][Start], (Start+fSamples<kNumberOfBins ? fSamples:(kNumberOfBins-Start)) * sizeof(short)); 1362 Pnt += (Start+fSamples<kNumberOfBins ? fSamples:(kNumberOfBins-Start)) * sizeof(short); 1363 // In case second part of waveform still missing, write now 1364 if((Start+fSamples<kNumberOfBins ? fSamples:(kNumberOfBins-Start)) * sizeof(short) < fSamples * sizeof(short)) { 1365 memcpy(Pnt, &WaveForm[i][k][l][0], (fSamples-(kNumberOfBins-Start)) * sizeof(short)); 1366 } 1367 } 1368 } 1369 } 1370 EventService->updateService((void *) DIMEventData, DIMSize); 1371 } 1372 1373 // Write updated run header, close file 1374 RunSize += FileSize; 1375 WriteError |= !UpdateRunHeader(EventsInFile, WriteError); 1376 if(close(Rawfile) == -1) PrintMessage("Error: Could not close data file (%s)\n", strerror(errno)); 1377 else PrintMessage("Data file closed (size %lu MByte).\n", FileSize/1024/1024); 1378 1379 FileNumber += 1; 1380 } while((NumEvents<NumEventsRequested || NumEventsRequested==0) && !Stop && !WriteError); 1381 1382 StopDRS(); 1383 1384 // Print run summary to screen 1385 if(!WriteError) PrintMessage("\rRun #%d (%s) %s, %d events\n", RunNumber, daq_runtype_str[daq_runtype], (NumEvents == NumEventsRequested) ? "completed":"stopped", NumEvents); 1386 else PrintMessage("\rRun #%d (%s) aborted due to error after %d events\n", RunNumber, daq_runtype_str[daq_runtype], NumEvents); 1387 1388 // Write run summary to slow data file 1389 //m->SlowDataClass->NewEntry("Runinfo"); 1390 //m->SlowDataClass->AddToEntry("%d %s %s %d %d %s", m->RunNumber, WriteError?"Error":"OK", daq_runtype_str[m->daq_runtype], m->NumEvents, m->FileNumber, m->RHeader->Description); 1391 1392 // Print run statistics 1393 if (NumEvents>0 && !WriteError) { 1394 gettimeofday(&StopTime, NULL); 1395 float RunTime = StopTime.tv_sec-StartTime.tv_sec + (StopTime.tv_usec-StartTime.tv_usec)*1e-6; 1396 PrintMessage("Time for run %.2f seconds, trigger rate %.2f Hz.\n", RunTime, NumEvents/RunTime); 1397 PrintMessage("Run size %llu MByte, data rate %.1f MByte/s.\n", RunSize/1024/1024, RunSize/1024.0/1024/RunTime); 1398 } 1399 1400 daq_state = stopped; 1401 } 1191 1402 1192 1403 // --------------------------------------- … … 1228 1439 } 1229 1440 1230 1231 /********************************************************************\ 1232 1233 DAQ Thread 1234 1235 This thread takes data until the requested number of events is reached, 1236 until no more disk space is available or until data taking is stopped. 1237 No mutex mechanism is used since variables will never be written 1238 simultaneoously by two threads. 1239 1240 \********************************************************************/ 1241 1441 // Thread entry routines (non-static class methods cannot be directly executed as thread) 1242 1442 void DAQ(DAQReadout *m) { 1243 1443 1244 struct timeval StartTime, StopTime; 1245 unsigned int EventsInFile; 1246 unsigned long long RunSize = 0; 1247 bool WriteError = false; 1248 off_t FileSize; 1249 1250 m->NumEvents = 0; 1251 m->FileNumber = 0; 1252 m->HVFB->ClearAverages(); 1253 gettimeofday(&StartTime, NULL); 1254 m->PrintMessage("\rStarting run #%d (%s) with %u event(s)\n",m->RunNumber,daq_runtype_str[m->daq_runtype],m->NumEventsRequested); 1255 1256 do { 1257 // Check if enough disk space is left 1258 if (CheckDisk(m->fRawDataPath) <= m->fMinDiskSpaceMB+m->fMaxFileSizeMB) { 1259 m->PrintMessage("\rError: Disk space after next file (max. %d MByte) below %d MByte\n",m->fMaxFileSizeMB,m->fMinDiskSpaceMB); 1260 break; 1261 } 1262 1263 // Init run header, open raw file, write run header 1264 if (!m->OpenRawFile()) break; 1265 m->PrintMessage("\rData file \"%s\" opened.\n",m->FileName); 1266 EventsInFile = 0; 1267 FileSize = 0; 1268 1269 WriteError |= !m->WriteRunHeader(); 1270 1271 if (m->daq_runtype != test) m->StartDRS(); 1272 1273 // Take data until finished, stopped or file too large 1274 while ((m->NumEvents<m->NumEventsRequested || m->NumEventsRequested==0) && 1275 !m->Stop && FileSize/1024/1024<m->fMaxFileSizeMB && !WriteError) { 1276 1277 if (m->daq_runtype == data) while (m->IsDRSBusy()); // Wait for hardware trigger (if DAQ stopped, DRS will not be busy anymore) 1278 else if (m->daq_runtype == pedestal) m->StopDRS(); // ..or for software trigger 1279 1280 // Read event data via VME or generate test data (for one board if no boards available) 1281 if (m->daq_runtype != test) { 1282 m->ReadCalibratedDRSData(); 1283 m->StartDRS(); // Restart here: writing data is in parallel to waiting for next trigger 1284 } 1285 else { 1286 double Period = ((double) rand())/RAND_MAX*20; 1287 for (long unsigned int i=0; i<m->RHeader->NBoards*m->RHeader->NChips*m->RHeader->NChannels*m->RHeader->Samples; i++) 1288 *((short *) m->WaveForm+i) = (short) (sin(i/Period)*1000); 1289 } 1290 1291 // Write event to disk and update file size 1292 EventsInFile++; m->NumEvents++; 1293 WriteError |= !m->WriteEvent(); 1294 1295 if((FileSize = lseek(m->Rawfile, 0, SEEK_CUR)) == -1) { 1296 m->PrintMessage("Error: Could not determine file size, terminating run (%s)\n", strerror(errno)); 1297 WriteError = true; 1298 } 1299 1300 // Call feedback to process event 1301 m->HVFB->ProcessEvent(); 1302 } 1303 1304 // Write updated run header, close file 1305 RunSize += FileSize; 1306 WriteError |= !m->UpdateRunHeader(EventsInFile, WriteError); 1307 if(close(m->Rawfile)==-1) m->PrintMessage("Error: Could not close data file (%s)\n", strerror(errno)); 1308 else m->PrintMessage("Data file closed (size %lu MByte).\n", FileSize/1024/1024); 1309 1310 m->FileNumber += 1; 1311 } while((m->NumEvents<m->NumEventsRequested || m->NumEventsRequested==0) && !m->Stop && !WriteError); 1312 1313 m->StopDRS(); 1314 1315 // Print run summary to screen 1316 if(!WriteError) m->PrintMessage("\rRun #%d (%s) %s, %d events\n",m->RunNumber,daq_runtype_str[m->daq_runtype],(m->NumEvents == m->NumEventsRequested) ? "completed":"stopped",m->NumEvents); 1317 else m->PrintMessage("\rRun #%d (%s) aborted due to error after %d events\n",m->RunNumber,daq_runtype_str[m->daq_runtype],m->NumEvents); 1318 1319 // Write run summary to slow data file 1320 //m->SlowDataClass->NewEntry("Runinfo"); 1321 //m->SlowDataClass->AddToEntry("%d %s %s %d %d %s", m->RunNumber, WriteError?"Error":"OK", daq_runtype_str[m->daq_runtype], m->NumEvents, m->FileNumber, m->RHeader->Description); 1322 1323 // Print run statistics 1324 if (m->NumEvents>0 && !WriteError) { 1325 gettimeofday(&StopTime, NULL); 1326 float RunTime = StopTime.tv_sec-StartTime.tv_sec + (StopTime.tv_usec-StartTime.tv_usec)*1e-6; 1327 m->PrintMessage("Time for run %.2f seconds, trigger rate %.2f Hz.\n", RunTime, m->NumEvents/RunTime); 1328 m->PrintMessage("Run size %llu MByte, data rate %.1f MByte/s.\n", RunSize/1024/1024, RunSize/1024.0/1024/RunTime); 1329 } 1330 1331 m->daq_state = stopped; 1332 } 1333 1334 1335 /********************************************************************\ 1336 1337 DAQ Thread - no disk writing, only hardware trigger, for feedback tests 1338 1339 \********************************************************************/ 1340 1341 void DAQ_Silent(DAQReadout *m) { 1342 1343 m->PrintMessage("\rData taking started\n"); 1344 do { 1345 // Start DRS and wait for hardware trigger 1346 m->StartDRS(); 1347 while (m->IsDRSBusy()); 1348 1349 // Read event data via VME and call feedback 1350 m->ReadCalibratedDRSData(); 1351 m->HVFB->ProcessEvent(); 1352 } while(!m->Stop); 1353 1354 m->PrintMessage("\rData taking stopped\n"); 1355 m->daq_state = stopped; 1356 } 1444 m->DAQ(); 1445 } 1446 1447 void Execute(char *Command) { 1448 1449 This->Execute(Command); 1450 free(Command); 1451 } -
drsdaq/DAQReadout.h
r193 r211 1 1 #ifndef DAQREADOUT_H_SEEN 2 2 #define DAQREADOUT_H_SEEN 3 4 #define SERVER_NAME "drsdaq" // Name to use in DIM 5 #include "Evidence.h" 3 6 4 7 #include <stdlib.h> … … 26 29 #define MsgToConsole 1 27 30 #define MsgToLog 2 28 #define MsgToSocket 429 31 30 32 enum state_enum {active, stopped}; 31 33 enum runtype_enum {data, pedestal, reserved, test}; 32 34 33 class DAQReadout : public DRS, public DRSCallback, public EvidenceServer { 35 class DAQReadout : public DRS, public DRSCallback, public DimCommand, public EvidenceServer { 36 34 37 time_t StartTime; 38 pid_t MainThread; 39 DimService *EventService; 40 int MinDelay; 41 unsigned int CmdNumber; 35 42 36 pthread_t thread_DAQ;37 pthread_t thread_DAQ_Silent;43 void PrintUsage(); 44 void commandHandler(); 38 45 39 unsigned int CmdNumber; 40 void PrintUsage(); 41 42 public: 43 RunHeader* RHeader; 44 EventHeader* EHeader; 45 46 short (*WaveForm)[kNumberOfChipsMax][kNumberOfChannelsMax][kNumberOfBins]; 47 int (*TriggerCell)[kNumberOfChipsMax]; 48 49 pthread_mutex_t control_mutex; 46 pthread_mutex_t Mutex; 50 47 int Rawfile; 51 48 class HVFeedback* HVFB; … … 58 55 int fFirstSample; 59 56 unsigned int fSamples; 60 int fCCPort;61 57 double fDefaultFrequency; 58 59 state_enum daq_state; 60 runtype_enum daq_runtype; 61 bool Stop; // Set to true to stop run 62 unsigned int NumEvents; // Number of event taken 63 unsigned int NumEventsRequested; // Number of events requested 64 int RunNumber; 65 unsigned int FileNumber; 66 char FileName[MAX_PATH]; 67 char CalibInfoFilename[MAX_PATH]; 68 69 public: 70 RunHeader* RHeader; 71 EventHeader* EHeader; 72 BoardStructure *BStruct; 62 73 63 // Status variables 74 short (*WaveForm)[kNumberOfChipsMax][kNumberOfChannelsMax][kNumberOfBins]; 75 int (*TriggerCell)[kNumberOfChipsMax]; 76 char *DIMEventData; 77 78 char Prompt[MAX_COM_SIZE]; 79 64 80 int NParam; // Number of command parameters 65 81 const char *Param[MAX_NUM_TOKEN]; // Pointers to parameters 66 bool CmdFromSocket; // Current command issued via socket67 82 int NumBoards; 68 83 int FirstBoard; … … 72 87 double *ACalibTemp; 73 88 bool *TCalib; 74 75 BoardStructure *BStruct; 76 state_enum daq_state; 77 runtype_enum daq_runtype; 78 int Socket; // -1 if not connected 79 pthread_t *SocketThread; // exit function sends signal to this thread 80 bool Exit; 81 bool Stop; // Set to true to stop run 82 unsigned int NumEvents; // Number of event taken 83 unsigned int NumEventsRequested; // Number of events requested 84 int RunNumber; 85 unsigned int FileNumber; 86 char FileName[MAX_PATH]; 87 char Prompt[MAX_COM_SIZE]; 88 char CalibInfoFilename[MAX_PATH]; 89 90 // Public functions 89 91 90 DAQReadout(); 92 91 ~DAQReadout(); … … 94 93 void cmd_exit(); void cmd_help(); 95 94 void cmd_board(); void cmd_status(); 96 void cmd_led(); void cmd_freq();95 void cmd_led(); void cmd_freq(); 97 96 void cmd_acalib(); void cmd_serial(); 98 97 void cmd_trigger(); void cmd_centre(); … … 103 102 void cmd_eepromtest(); void cmd_tcalib(); 104 103 void cmd_regtest(); void cmd_ramtest(); 105 void cmd_start(); void cmd_take();104 void cmd_take(); void cmd_update(); 106 105 void cmd_config(); void cmd_events(); 107 106 void cmd_disk(); void cmd_uptime(); … … 111 110 void cmd_fresponse(); void cmd_fconfig(); 112 111 113 void CommandControl(char*);112 void Execute(char*); 114 113 void StartDRS(); 115 114 void StopDRS(); … … 133 132 bool UpdateRunHeader(unsigned int, bool); 134 133 bool WriteEvent(); 134 void DAQ(); 135 135 136 136 void Progress(int); … … 138 138 139 139 void DAQ(DAQReadout *); 140 void DAQ_Silent(DAQReadout*);140 void Execute(char *); 141 141 142 142 bool Match(const char*, const char*); -
drsdaq/HVFeedback.cc
r196 r211 57 57 58 58 char *Token = strtok(m->GetConfig("DefaultResponse"), " \t"); 59 for (int i=0; i<m->NumBoards*fNumberOfChips*fNumberOfChannels; i++) { 60 if (Token == NULL) break; 61 *(&Response[0][0][0]+i) = (float) atof(Token); 62 Token = strtok(NULL, " \t"); 63 } 59 for (int i=0; i<m->NumBoards; i++) { 60 for (int j=0; j<fNumberOfChips; j++) { 61 for (int k=0; k<fNumberOfChannels; k++) { 62 if (Token == NULL) break; 63 Response[i][j][k] = (float) atof(Token); 64 Token = strtok(NULL, " \t"); 65 } 66 } 67 } 68 64 69 Token = strtok(m->GetConfig("DefaultTarget"), " \t"); 65 for (int i=0; i<m->NumBoards*fNumberOfChips*fNumberOfChannels; i++) { 66 if (Token == NULL) break; 67 *(&Target[0][0][0]+i) = (float) atof(Token); 68 Token = strtok(NULL, " \t"); 69 } 70 70 for (int i=0; i<m->NumBoards; i++) { 71 for (int j=0; j<fNumberOfChips; j++) { 72 for (int k=0; k<fNumberOfChannels; k++) { 73 if (Token == NULL) break; 74 Target[i][j][k] = (float) atof(Token); 75 Token = strtok(NULL, " \t"); 76 } 77 } 78 } 79 71 80 PrintConfig(MsgToLog); 72 81 … … 79 88 80 89 // Initial state 81 Gain = atof(m->GetConfig("DefaultGain")); printf("Gain %d\n", Gain);90 Gain = atof(m->GetConfig("DefaultGain")); 82 91 SetFBMode(FB_Off); 83 92 SetNumAverages(fDefaultNumAverage); -
drsdaq/HVFeedback.h
r182 r211 6 6 #include <stdlib.h> 7 7 #include <math.h> 8 9 #define SERVER_NAME "Feedback" // Name to use in DIM10 #include "Evidence.h"11 8 12 9 #include "RawDataCTX.h" -
drsdaq/History.txt
r182 r211 61 61 11/3/2010 Removed SlowData class. 62 62 12/3/2010 Removed local configuration and logging. 63 30/4/2010 Command 'start' now starts a normal run as 'take', but data is written to 64 /dev/null, the run number is -1. 65 4/5/2010 Removed socket server, added DIM command handler (thus cannot communicate 66 with ddd over socket anymore). Added DIM service containing full event. 67 18/5/2010 Rate of event service adjustable with command 'update'. 68 21/5/2010 Fix so that 'exit' command also works as DimCommand. -
drsdaq/drsdaq.cpp
r182 r211 1 1 /**************************************************************\ 2 2 3 drsdaq .cpp3 drsdaq 4 4 5 Main program for DRS CTX DAQ system. Global initialization, 6 starts threads for console input and socket interface. 5 Main program for data acquisition, starts threads for console input. 7 6 8 Sebastian Commichau, Oliver Grimm 7 Original program by S. Commichau. 8 9 Oliver Grimm, May 2010 9 10 10 11 \**************************************************************/ 11 12 12 #define DEFAULT_CONFIG "../config/DRSDAQ.conf" // Default configuration file13 13 #define LOCKFILE "/tmp/CT3_DAQ_LOCK" 14 14 15 15 #include <stdio.h> 16 16 #include <signal.h> 17 #include <pthread.h>18 #include <sys/socket.h>19 #include <netdb.h>20 #include <arpa/inet.h>21 17 #include <readline/readline.h> 22 18 #include <readline/history.h> … … 26 22 27 23 // Function prototypes 28 void ConsoleCommand(DAQReadout *);29 void CCCommand(DAQReadout *);30 void SignalHandler(int);31 24 void CrashHandler(int); 32 25 void ExitFunction(); … … 38 31 // Several unlikely system call failures are handled via throwing an exception. 39 32 40 int main( int argc, char *argv[]) {33 int main() { 41 34 42 char str[MAX_COM_SIZE]; 43 pthread_t thread_ConsoleCommand, thread_CCCommand; 35 char str[MAX_COM_SIZE], *Command; 44 36 int LockDescriptor; 45 46 // writev() in DAQ thread needs to be able to write at least 3 chunks 47 if(IOV_MAX < 3) { 48 printf("Fatal error: IOV_MAX is less than 3, cannot use writev() to write event data.\n"); 49 exit(EXIT_FAILURE); 50 } 37 38 // Readline library uses getc() (allows interruption by signal) 39 rl_getc_function = getc; 40 41 // writev() in DAQ thread needs to be able to write at least 3 chunks 42 if(IOV_MAX < 3) { 43 printf("Fatal error: IOV_MAX is less than 3, cannot use writev() to write event data.\n"); 44 exit(EXIT_FAILURE); 45 } 51 46 52 // Interpret command line (do before lockfile creation in case of exit())53 if((argc==3 && strcmp(argv[1],"-c")!=0) || argc==2) {54 printf("Usage: %s [-c <ConfigFile>] Default file is \"%s\"\n", argv[0], DEFAULT_CONFIG);55 exit(EXIT_SUCCESS);56 }57 58 47 // Assure only one instance of program runs (lock creator written to log file) 48 // Lock file deleted by ExitFunction() 59 49 if((LockDescriptor = open(LOCKFILE,O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)) == -1) { 60 50 if(errno==EEXIST) { 61 51 printf("Error: Lock file already existing\n"); 62 s printf(str,"paste %s -s -d ' '",LOCKFILE);52 snprintf(str, sizeof(str), "paste %s -s -d ' '",LOCKFILE); 63 53 system(str); 64 54 } … … 71 61 72 62 system("clear"); 73 printf("\n*** DRS readout built %s, %s (revision %s) *** \n\n",__DATE__, __TIME__, REVISION);63 printf("\n*** DRS readout (built %s, %s, revision %s) *** \n\n",__DATE__, __TIME__, REVISION); 74 64 75 // Set signal handlers 76 signal(SIGUSR1, &SignalHandler); 77 siginterrupt (SIGUSR1, true); // Set SIGUSR1 to interrupt (and not restart) blocking system calls 78 signal(SIGQUIT, &CrashHandler); 65 // Construct main instance (static ensures destructor is called with exit()) 66 static DAQReadout M; 67 68 // Set signal and exit handlers 69 atexit(&ExitFunction); 79 70 signal(SIGILL, &CrashHandler); 80 71 signal(SIGABRT, &CrashHandler); … … 82 73 signal(SIGSEGV, &CrashHandler); 83 74 signal(SIGBUS, &CrashHandler); 84 signal(SIGTERM, &CrashHandler);85 signal(SIGINT, &CrashHandler);86 signal(SIGHUP, &CrashHandler);87 atexit(&ExitFunction);88 75 89 // Construct main instance and create mutex for thread synchronization 90 DAQReadout dreadout; 91 if (pthread_mutex_init(&dreadout.control_mutex, NULL) != 0) { 92 perror("pthread_mutex_init failed"); 93 throw; 94 } 95 96 // Create threads 97 if (pthread_mutex_init(&dreadout.control_mutex, NULL) != 0) { 98 perror("pthread_mutex_init failed"); 99 throw; 100 } 101 if ((pthread_create(&thread_ConsoleCommand, NULL, (void * (*)(void *)) ConsoleCommand,(void *) &dreadout)) != 0) { 102 perror("pthread_create failed with console thread"); 103 throw; 104 } 105 if ((pthread_create(&thread_CCCommand, NULL, (void * (*)(void *)) CCCommand,(void *) &dreadout)) != 0) { 106 perror("pthread_create failed with socket thread"); 107 dreadout.SocketThread = NULL; 108 } 109 else dreadout.SocketThread = &thread_CCCommand; // Thread should be accessible for sending signals 110 111 // Wait for threads to quit 112 pthread_join(thread_ConsoleCommand, NULL); 113 if(dreadout.SocketThread != NULL) pthread_join(thread_CCCommand, NULL); 114 115 // Destruct mutex and main instance 116 pthread_mutex_destroy (&dreadout.control_mutex); 117 dreadout.~DAQReadout(); 118 119 // Remove lockfile 120 if (remove(LOCKFILE)==-1) { 121 printf("Could not remove lock file %s (%s)\n", LOCKFILE, strerror(errno)); 122 exit(EXIT_FAILURE); 123 } 124 exit(EXIT_SUCCESS); 125 } 126 127 128 /********************************************************************\ 129 130 ConsoleCommand thread 131 132 Handle console input using readline library functions to allow 133 line editing and history capability 134 135 \********************************************************************/ 136 137 void ConsoleCommand(DAQReadout *m) { 138 139 char *Command; 140 141 while (!m->Exit) { 142 76 // Command loop 77 while (!M.ExitRequest) { 143 78 // Assemble prompt 144 if ( m->NumBoards == 0) snprintf(m->Prompt,sizeof(m->Prompt),"\rDAQ> ");145 else if ( m->FirstBoard == m->LastBoard) snprintf(m->Prompt,sizeof(m->Prompt),"\rDAQ|B%d> ",m->FirstBoard);146 else snprintf( m->Prompt,sizeof(m->Prompt),"\rDAQ|B%d-%d> ",m->FirstBoard,m->LastBoard);79 if (M.NumBoards == 0) snprintf(M.Prompt,sizeof(M.Prompt),"\rDAQ> "); 80 else if (M.FirstBoard == M.LastBoard) snprintf(M.Prompt,sizeof(M.Prompt),"\rDAQ|B%d> ",M.FirstBoard); 81 else snprintf(M.Prompt,sizeof(M.Prompt),"\rDAQ|B%d-%d> ",M.FirstBoard,M.LastBoard); 147 82 148 83 // Read Command 149 Command = readline(m->Prompt); 150 if (Command == NULL) { 151 m->PrintMessage("Error reading command line input\n"); 152 continue; 153 } 84 Command = readline(M.Prompt); 85 if (Command == NULL) continue; 154 86 if(strlen(Command)>0) add_history(Command); 155 87 156 // Log command157 m->PrintMessage(MsgToLog, "CONSOLE> %s\n", Command);158 159 88 // Process command 160 pthread_mutex_lock(&m->control_mutex); 161 m->CommandControl(Command); 162 pthread_mutex_unlock(&m->control_mutex); 89 DimClient::sendCommand(SERVER_NAME"/Command", Command); 163 90 164 91 free(Command); 165 } 92 } 166 93 } 167 94 168 95 169 170 /********************************************************************\ 171 172 CCCommand thread 173 174 Listen to commands from socket (Central Control) 175 176 This thread will block execution in the accept() and read() socket function 177 while waiting for a connection or data. If the exit function is invoked through 178 keyboard command, these blocking functions are interrupted by raising the signal 179 SIGUSR1. Testing on errno=EINTR indicates this termination. The dummy signal 180 handler below is needed to prevent the standard thread termination occurring 181 when this signal is received. 182 183 \********************************************************************/ 184 185 void CCCommand(DAQReadout *m) { 186 187 int ServerSocket,ConnectionSocket,ReadResult; 188 struct sockaddr_in SocketAddress, ClientAddress; 189 struct hostent *ClientName; 190 socklen_t SizeClientAddress=sizeof(ClientAddress); 191 char Command[MAX_COM_SIZE]; 192 193 // Set up server socket 194 if ((ServerSocket = socket(PF_INET, SOCK_STREAM, 0)) == -1) { 195 m->PrintMessage("Could not open server socket, no remote connection possible (%s).\n", strerror(errno)); 196 return; 197 } 198 // Allows immediate reuse of socket after closing (circumvents TIME_WAIT) 199 int Value=1; 200 if (setsockopt(ServerSocket, SOL_SOCKET, SO_REUSEADDR, (char *) &Value, sizeof (Value)) == -1) { 201 m->PrintMessage("Warning: Could not set server socket option SO_REUSEADDR (%s)\n", strerror(errno)); 202 } 203 204 SocketAddress.sin_family = PF_INET; 205 SocketAddress.sin_port = htons((unsigned short) m->fCCPort); 206 SocketAddress.sin_addr.s_addr = INADDR_ANY; 207 208 if (bind(ServerSocket, (struct sockaddr *) &SocketAddress, sizeof(SocketAddress)) == -1) 209 { 210 m->PrintMessage("Could not bind port to socket (%s)\n", strerror(errno)); 211 close(ServerSocket); 212 return; 213 } 214 if (listen(ServerSocket, 0) == -1) { 215 m->PrintMessage("Could not set socket to listening (%s)\n", strerror(errno)); 216 close(ServerSocket); 217 return; 218 } 219 220 // Looping to wait for incoming connection 221 while (!m->Exit) { 222 if ((ConnectionSocket = accept(ServerSocket, (struct sockaddr *) &ClientAddress, &SizeClientAddress)) == -1) { 223 if (errno!=EINTR) m->PrintMessage("Failed to accept incoming connection (%s)\n", strerror(errno)); 224 close(ServerSocket); 225 return; 226 } 227 228 ClientName = gethostbyaddr((char *) &ClientAddress.sin_addr ,sizeof(struct sockaddr_in),AF_INET); 229 m->PrintMessage("Connected to client at %s (%s).\n", inet_ntoa(ClientAddress.sin_addr), ClientName!=NULL ? ClientName->h_name:"name unknown"); 230 m->Socket = ConnectionSocket; 231 232 // Looping as long as client exists and program not terminated 233 while (!m->Exit) { 234 235 // Try to read command from socket 236 memset(Command,0,sizeof(Command)); 237 ReadResult = read(ConnectionSocket, Command, MAX_COM_SIZE); 238 if (ReadResult==0) break; // Client not exisiting anymore 239 if (ReadResult==-1) { 240 if (errno!=EINTR) m->PrintMessage("Error read from socket (%s)\n", strerror(errno)); 241 break; 242 } 243 if (Command[strlen(Command)-1]=='\n') Command[strlen(Command)-1]='\0'; // Remove trailing newline 244 245 // Log command 246 m->PrintMessage(MsgToConsole|MsgToLog, "SOCKET> %s\n", Command); 247 248 // Process command 249 pthread_mutex_lock(&m->control_mutex); 250 m->CmdFromSocket = true; 251 m->CommandControl(Command); 252 m->CmdFromSocket = false; 253 pthread_mutex_unlock(&m->control_mutex); 254 } 255 256 m->Socket = -1; 257 m->PrintMessage("Disconnected from client.\n"); 258 close(ConnectionSocket); 259 } 260 close(ServerSocket); 261 m->PrintMessage("Server socket closed.\n"); 262 } 263 264 265 /********************************************************************\ 266 267 Signal handlers 268 269 \********************************************************************/ 96 //***************** 97 // Signal handlers 98 //***************** 270 99 271 100 // Remove lock file before running default signal code … … 277 106 } 278 107 279 // Dummy signal handler to return from blocking syscalls280 void SignalHandler(int Signal) {281 return;282 }283 284 108 // This function will be implicitly called by exit() 285 109 void ExitFunction() { 286 remove(LOCKFILE); 110 111 if (remove(LOCKFILE)==-1) { 112 printf("Could not remove lock file %s (%s)\n", LOCKFILE, strerror(errno)); 113 } 114 287 115 return; 288 116 }
Note:
See TracChangeset
for help on using the changeset viewer.