Changeset 211


Ignore:
Timestamp:
May 21, 2010, 1:31:27 PM (11 years ago)
Author:
ogrimm
Message:
Fix for exit signalling from DimCommand thread
Location:
drsdaq
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • drsdaq/DAQReadout.cc

    r193 r211  
    3434   {"take", &DAQReadout::cmd_take, false, "<d|p|t> [n] [source]", "Start run (data, pedestal or test) with n events"},
    3535   {"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"},
    3737   {"stop", &DAQReadout::cmd_stop, false, "", "Issue soft trigger and stop DAQ"},
    3838   {"regtest", &DAQReadout::cmd_regtest, true, "", "DRS register test"},
     
    4545   {"disk", &DAQReadout::cmd_disk, false, "" ,"Remaining disk space"},
    4646   {"uptime", &DAQReadout::cmd_uptime, false, "", "Get DAQ uptime"},             
     47   {"update", &DAQReadout::cmd_update, false, "<sec>", "Minimum delay between updates to DIM event service"},             
    4748   {"exit", &DAQReadout::cmd_exit, false, "", "Exit program"},
    4849   {"fmode", &DAQReadout::cmd_fmode, false, "[off|active|targ]", "Set or get feedback mode"},
     
    5556
    5657
     58// Global pointer for thread entry routines
     59class DAQReadout *This;
     60
    5761// -----------------------------------------------
    5862// *****  Constructor: Class initialisation  *****
     
    6064//
    6165 
    62 DAQReadout::DAQReadout() :EvidenceServer(SERVER_NAME) {
    63    
    64   time(&StartTime);  // Start time of DAQ
     66DAQReadout::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  }
    6581
    6682  // 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;
    7791 
    7892  // Get configuration data
     
    8397  fMinDiskSpaceMB = atoi(GetConfig("MinDiskSpaceMB"));
    8498  fMaxFileSizeMB = atoi(GetConfig("MaxFileSizeMB"));
    85   fCCPort = atoi(GetConfig("CCPort"));
    8699  fDefaultFrequency = atof(GetConfig("DefaultFrequency"));
    87100
     
    106119  TCalib = new bool [NumBoards];
    107120
    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");
    109122
    110123  for (int i=0; i<NumBoards; i++) {
     
    121134  WaveForm = new short [NumBoards == 0 ? 1:NumBoards][kNumberOfChipsMax][kNumberOfChannelsMax][kNumberOfBins];
    122135  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)
    125146  HVFB    = new HVFeedback(this); 
    126147}
     
    132153DAQReadout::~DAQReadout() {
    133154
    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");
    139165}
    140166
     
    143169// --------------------------------
    144170
    145 void DAQReadout::CommandControl(char *Command) {
     171void DAQReadout::Execute(char *Command) {
    146172
    147173  if (strlen(Command)==0) return;  // Ignore empty commands
     
    158184    if (Match(Param[0], CommandList[CmdNumber].Name)) {
    159185      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          }
    162192      return; 
    163193    }
    164194  PrintMessage("Unknown command '%s'\n",Param[0]);
    165   return;
    166195}
    167196         
     
    186215// Print DAQ configuration
    187216void DAQReadout::cmd_config() {
    188   PrintConfig(CmdFromSocket ? MsgToSocket : MsgToConsole);
     217  PrintConfig(MsgToConsole);
    189218}
    190219
     
    202231    for (int i=FirstBoard; i<=LastBoard-1; i++) {
    203232      if ((GetBoard(i)->GetNumberOfChannels() != GetBoard(i+1)->GetNumberOfChannels()) || (GetBoard(i)->GetNumberOfChips() != GetBoard(i+1)->GetNumberOfChips())) {
    204         PrintMessage("Cannot take data is not 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");
    205234        return;
    206235      }
     
    241270  else snprintf(RHeader->Description,sizeof(RHeader->Description),"DUMMY");
    242271
    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;
    251285
    252286  // 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  }
    255292  else {
    256293    daq_state = active;
    257294    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        }
    259298  } 
    260299}
    261300 
    262 // Start DRS
    263 void DAQReadout::cmd_start() {
    264   if (IsDRSFreqSet()) {
    265     StartDRS();
    266     PrintMessage("Domino wave started\n");
    267    
    268       // Create DAQ thread
    269     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 
    279301// EEPROM test
    280302void DAQReadout::cmd_eepromtest() {
     
    366388  }
    367389
    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());
    370391  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");
    381396  PrintMessage(MsgToConsole, "Trigger cell: %d\n", TriggerCell[Board][Chip]); 
    382   printf("rms: %f\n",sqrt(square/kNumberOfBins - pow(mean/kNumberOfBins,2)));
    383397}
    384398
     
    614628                " Storage directory: %s\n"
    615629                " Disk space: %lu MByte\n"
    616                 " Socket state: %s\n"                             
    617630                " Total number of DRS boards: %d\n"
    618631                " Active DRS boards: %d\n",
     
    620633      daq_state==active ? daq_runtype_str[daq_runtype]:"n/a", NumEvents,
    621634      NumEventsRequested, fRawDataPath,
    622       CheckDisk(fRawDataPath), Socket==-1 ? "disconnected":"connected",
    623       NumBoards, LastBoard - FirstBoard + 1);
     635      CheckDisk(fRawDataPath), NumBoards, LastBoard - FirstBoard + 1);
    624636
    625637    for (int i=FirstBoard;i<=LastBoard;i++)
     
    705717}
    706718
    707 // Print help (only to console or socket, not to log file)
     719// Set input range
     720void 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
    708730void DAQReadout::cmd_help() {
     731
    709732  char Buffer[MAX_COM_SIZE];
     733
    710734  for(unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) {
    711735    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);
    713737  }     
    714   PrintMessage(CmdFromSocket ? MsgToSocket:MsgToConsole,".<command>                  Execute shell command\n\n"
     738  PrintMessage(MsgToConsole,".<command>                  Execute shell command\n\n"
    715739   "Items in <> are mandatory, in [] optional, | indicates mutual exclusive or.\n"
    716740   "Test data can also be written if no DRS boards are available.\n"
     
    718742}
    719743
    720 // Exit programm
     744// Exit programm - SIGTERM sets ExitRequest flag
     745// If command comes from DimCommand thread, SIGTERM also makes readline() return
    721746void 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); 
    731750}
    732751
    733752// Set/get mode of feedback
    734753void DAQReadout::cmd_fmode() {
     754
    735755  if(Match(Param[1],"off")) HVFB->SetFBMode(FB_Off);
    736756  if(Match(Param[1],"active")) HVFB->SetFBMode(FB_Active);
     
    741761// Set/get current number of events
    742762void DAQReadout::cmd_faverage() {
     763
    743764  if(NParam==1) PrintMessage("Current number of feedback events: %u   (acting when %u events are reached)\n",
    744765                       HVFB->GetCurrentCount(), HVFB->GetNumAverages());
     
    749770// Set/get feedback gain
    750771void DAQReadout::cmd_fgain() {
     772
    751773  if(NParam==2) HVFB->SetGain(atof(Param[1]));
    752774  PrintMessage("Feedback gain is %.2f\n", HVFB->GetGain());
     
    755777// Set/get target value
    756778void DAQReadout::cmd_ftarget() {
     779
    757780  if(NParam==1) HVFB->GetTargets();
    758781  else if(NParam!=5) PrintUsage();
     
    768791// Start response measurement
    769792void DAQReadout::cmd_fresponse() {
     793
    770794  if(NParam==1) HVFB->GetResponse();
    771795  else if(atof(Param[1])) HVFB->MeasureResponse(atof(Param[1]));
     
    775799// Print feedback configuration
    776800void DAQReadout::cmd_fconfig() {
    777   HVFB->PrintConfig(CmdFromSocket ? MsgToSocket : MsgToConsole);
     801
     802  HVFB->PrintConfig(MsgToConsole);
    778803}
    779804
     
    940965}
    941966
    942 // Open new raw data file
     967// Open new raw data file (if RunNumber == -1, data will be written to /dev/null)
    943968bool DAQReadout::OpenRawFile() {
    944969
     
    955980
    956981  // 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        }
    961988  }
    962989 
    963990  // 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);
    966994 
    967995  //  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);
    969997  if(Rawfile==-1) {
    970998    PrintMessage("\rError: Could not open file \"%s\" (%s)\n", FileName, strerror(errno));
     
    10721100    return false;
    10731101  }
    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
    10781103  unsigned int Start, Count = 0;
    10791104  ssize_t WriteResult, Size = 0;
    10801105  struct iovec DataPart[IOV_MAX];
    10811106
     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
    10821122  // 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;
    10861126
    10871127  // Remaining chunks: ADC data (two chucks per channel if wrap around of pipeline occurred)
     
    11231163  PrintMessage(Target, "RawDataPath: %s\n"
    11241164               "DefaultFrequency: %.2f\tFirstSample: %d\tSamples: %u\n"
    1125                "MinDiskSpaceMB: %u\tMaxFileSizeMB: %d\tCCPort: %d\n"
     1165               "MinDiskSpaceMB: %u\tMaxFileSizeMB: %d\n"
    11261166                           "CalibDataPath: %s\n",
    11271167    fRawDataPath,fDefaultFrequency,fFirstSample,fSamples,fMinDiskSpaceMB,
    1128     fMaxFileSizeMB,fCCPort,fCalibDataPath);
     1168    fMaxFileSizeMB,fCalibDataPath);
    11291169}
    11301170
     
    11491189}
    11501190
    1151 // Print message to log file, and screen or socket (depending on command origin)
     1191// Print message to console only
    11521192void DAQReadout::PrintMessage(const char *Format, ...) {
    11531193  va_list ArgumentPointer;
    11541194  va_start(ArgumentPointer, Format);
    1155   if(CmdFromSocket) DoPrintMessage(Format, ArgumentPointer, MsgToSocket);
    1156   else DoPrintMessage(Format, ArgumentPointer, MsgToConsole);
     1195  DoPrintMessage(Format, ArgumentPointer, MsgToConsole);
    11571196  va_end(ArgumentPointer);
    11581197}
     
    11631202void DAQReadout::DoPrintMessage(const char *Format, va_list ArgumentPointer, int Target) {
    11641203
    1165   static char Textbuffer[MAX_COM_SIZE];  // static: it is only allocated once
    1166 
     1204  static char Textbuffer[MAX_COM_SIZE];
     1205 
    11671206  memset(Textbuffer, 0, sizeof(Textbuffer)); 
    11681207  vsnprintf(Textbuffer, sizeof(Textbuffer), Format, ArgumentPointer);
     
    11761215        fflush(stdout);
    11771216  }
     1217 
     1218  // Send to DIM service
     1219  SetStdOut(Textbuffer);
     1220
    11781221  // Send to log
    11791222  if(Target & MsgToLog) {
     
    11851228    else DimClient::sendCommandNB("DColl/Log", SERVER_NAME" asprintf() failed");
    11861229  }
    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)
     1233void 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
     1266void 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}
    11911402
    11921403// ---------------------------------------
     
    12281439}
    12291440
    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)
    12421442void DAQ(DAQReadout *m) {
    12431443
    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
     1447void Execute(char *Command) {
     1448
     1449 This->Execute(Command);
     1450 free(Command);
     1451}
  • drsdaq/DAQReadout.h

    r193 r211  
    11#ifndef DAQREADOUT_H_SEEN
    22#define DAQREADOUT_H_SEEN
     3
     4#define SERVER_NAME "drsdaq"       // Name to use in DIM
     5#include "Evidence.h"
    36
    47#include <stdlib.h>
     
    2629#define MsgToConsole 1
    2730#define MsgToLog 2
    28 #define MsgToSocket 4
    2931
    3032enum state_enum {active, stopped};
    3133enum runtype_enum {data, pedestal, reserved, test};
    3234
    33 class DAQReadout : public DRS, public DRSCallback, public EvidenceServer {
     35class DAQReadout : public DRS, public DRSCallback, public DimCommand, public EvidenceServer {
     36
    3437    time_t StartTime;
     38        pid_t MainThread;
     39        DimService *EventService;
     40        int MinDelay;
     41    unsigned int CmdNumber;
    3542
    36     pthread_t thread_DAQ;
    37     pthread_t thread_DAQ_Silent;
     43    void PrintUsage();
     44        void commandHandler();
    3845
    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;
    5047    int Rawfile;
    5148    class HVFeedback* HVFB;
     
    5855    int fFirstSample;
    5956    unsigned int fSamples;
    60     int fCCPort;
    6157    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;
    6273   
    63     // Status variables   
     74    short (*WaveForm)[kNumberOfChipsMax][kNumberOfChannelsMax][kNumberOfBins];
     75    int (*TriggerCell)[kNumberOfChipsMax];
     76        char *DIMEventData;
     77   
     78    char Prompt[MAX_COM_SIZE];
     79
    6480    int NParam;                 // Number of command parameters
    6581    const char *Param[MAX_NUM_TOKEN]; // Pointers to parameters
    66     bool CmdFromSocket;         // Current command issued via socket
    6782    int NumBoards;
    6883    int FirstBoard;
     
    7287    double *ACalibTemp;
    7388    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
    9190    DAQReadout();
    9291    ~DAQReadout();
     
    9493    void cmd_exit();       void cmd_help();
    9594    void cmd_board();      void cmd_status();
    96     void cmd_led();        void cmd_freq();
     95    void cmd_led();        void cmd_freq();
    9796    void cmd_acalib();     void cmd_serial();
    9897    void cmd_trigger();    void cmd_centre();
     
    103102    void cmd_eepromtest(); void cmd_tcalib();
    104103    void cmd_regtest();    void cmd_ramtest();
    105     void cmd_start();      void cmd_take();
     104        void cmd_take();           void cmd_update();
    106105    void cmd_config();     void cmd_events();
    107106    void cmd_disk();       void cmd_uptime();
     
    111110    void cmd_fresponse();  void cmd_fconfig();
    112111
    113     void CommandControl(char*); 
     112    void Execute(char*); 
    114113    void StartDRS();
    115114    void StopDRS();
     
    133132    bool UpdateRunHeader(unsigned int, bool);
    134133    bool WriteEvent();
     134        void DAQ();
    135135   
    136136    void Progress(int);
     
    138138
    139139void DAQ(DAQReadout *);
    140 void DAQ_Silent(DAQReadout *);
     140void Execute(char *);
    141141
    142142bool Match(const char*, const char*);
  • drsdaq/HVFeedback.cc

    r196 r211  
    5757
    5858  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
    6469  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 
    7180  PrintConfig(MsgToLog);
    7281
     
    7988
    8089  // Initial state
    81   Gain = atof(m->GetConfig("DefaultGain"));printf("Gain %d\n", Gain);
     90  Gain = atof(m->GetConfig("DefaultGain"));
    8291  SetFBMode(FB_Off);
    8392  SetNumAverages(fDefaultNumAverage);
  • drsdaq/HVFeedback.h

    r182 r211  
    66#include <stdlib.h>
    77#include <math.h>
    8 
    9 #define SERVER_NAME "Feedback"       // Name to use in DIM
    10 #include "Evidence.h"
    118
    129#include "RawDataCTX.h"
  • drsdaq/History.txt

    r182 r211  
    616111/3/2010       Removed SlowData class.                 
    626212/3/2010       Removed local configuration and logging.
     6330/4/2010       Command 'start' now starts a normal run as 'take', but data is written to
     64                        /dev/null, the run number is -1.
     654/5/2010        Removed socket server, added DIM command handler (thus cannot communicate
     66                        with ddd over socket anymore). Added DIM service containing full event.
     6718/5/2010       Rate of event service adjustable with command 'update'.
     6821/5/2010       Fix so that 'exit' command also works as DimCommand.
  • drsdaq/drsdaq.cpp

    r182 r211  
    11/**************************************************************\
    22
    3   drsdaq.cpp
     3  drsdaq
    44
    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.
    76 
    8   Sebastian Commichau, Oliver Grimm
     7  Original program by S. Commichau.
     8 
     9  Oliver Grimm, May 2010
    910 
    1011\**************************************************************/
    1112
    12 #define DEFAULT_CONFIG "../config/DRSDAQ.conf"  // Default configuration file
    1313#define LOCKFILE "/tmp/CT3_DAQ_LOCK"
    1414
    1515#include <stdio.h>
    1616#include <signal.h>
    17 #include <pthread.h>
    18 #include <sys/socket.h>
    19 #include <netdb.h>
    20 #include <arpa/inet.h>
    2117#include <readline/readline.h>
    2218#include <readline/history.h>
     
    2622
    2723// Function prototypes
    28 void ConsoleCommand(DAQReadout *);
    29 void CCCommand(DAQReadout *);
    30 void SignalHandler(int);
    3124void CrashHandler(int);
    3225void ExitFunction();
     
    3831// Several unlikely system call failures are handled via throwing an exception.
    3932
    40 int main(int argc, char *argv[]) {
     33int main() {
    4134
    42   char str[MAX_COM_SIZE];
    43   pthread_t thread_ConsoleCommand, thread_CCCommand;
     35  char str[MAX_COM_SIZE], *Command;
    4436  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  }
    5146   
    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 
    5847  // Assure only one instance of program runs (lock creator written to log file)
     48  // Lock file deleted by ExitFunction()
    5949  if((LockDescriptor = open(LOCKFILE,O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)) == -1) {
    6050    if(errno==EEXIST) {
    6151      printf("Error: Lock file already existing\n");
    62       sprintf(str,"paste %s -s -d ' '",LOCKFILE);
     52      snprintf(str, sizeof(str), "paste %s -s -d ' '",LOCKFILE);
    6353      system(str);
    6454    }
     
    7161 
    7262  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);
    7464
    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);
    7970  signal(SIGILL, &CrashHandler);
    8071  signal(SIGABRT, &CrashHandler);
     
    8273  signal(SIGSEGV, &CrashHandler);
    8374  signal(SIGBUS, &CrashHandler);
    84   signal(SIGTERM, &CrashHandler);
    85   signal(SIGINT, &CrashHandler);
    86   signal(SIGHUP, &CrashHandler);
    87   atexit(&ExitFunction);
    8875
    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) {
    14378    // 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);
    14782
    14883    // 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;
    15486    if(strlen(Command)>0) add_history(Command);
    15587
    156     // Log command
    157     m->PrintMessage(MsgToLog, "CONSOLE> %s\n", Command);
    158 
    15988    // 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);
    16390
    16491    free(Command);
    165   }
     92  } 
    16693}
    16794
    16895
    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//*****************
    27099
    271100// Remove lock file before running default signal code
     
    277106}
    278107
    279 // Dummy signal handler to return from blocking syscalls
    280 void SignalHandler(int Signal) {
    281   return;
    282 }
    283 
    284108// This function will be implicitly called by exit()
    285109void 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
    287115  return;         
    288116}
Note: See TracChangeset for help on using the changeset viewer.