Changeset 226


Ignore:
Timestamp:
Jun 18, 2010, 12:25:29 PM (10 years ago)
Author:
ogrimm
Message:
Small changes to mutex handling in hvcontrol and drsdaq
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • drsdaq/DAQReadout.cc

    r211 r226  
    6464//
    6565 
    66 DAQReadout::DAQReadout():
    67                         DimCommand((char *) SERVER_NAME"/Command", (char *) "C"),
    68                         EvidenceServer(SERVER_NAME) {
    69 
    70   // Global class pointer
     66DAQReadout::DAQReadout(): EvidenceServer(SERVER_NAME) {
     67
     68  // Initialization
    7169  This = this;
    7270  MainThread = getpid();
    73 
    74   // Start time of DAQ
     71  ConsoleText = NULL;
    7572  time(&StartTime);
     73
     74  // DIM console service used in PrintMessage()
     75  ConsoleOut = new DimService(SERVER_NAME"/ConsoleOut", (char *) "");
    7676
    7777  // Initialize mutex for thread synchronisation
    7878  if (pthread_mutex_init(&Mutex, NULL) != 0) {
    79     State(FATAL, "pthread_mutex_init() failed");
     79    Message(FATAL, "pthread_mutex_init() failed");
    8080  }
    8181
     
    8989  LastBoard                     = -1;
    9090  MinDelay                      = 1;
    91  
     91
    9292  // Get configuration data
    9393  fRawDataPath = GetConfig("RawDataPath");
     
    145145  // Create instance of HV feedback (must be called after board detection)
    146146  HVFB    = new HVFeedback(this); 
     147
     148  // Install DIM command (after all initialized)
     149  Command = new DimCommand((char *) SERVER_NAME"/Command", (char *) "C", this);
    147150}
    148151
     
    153156DAQReadout::~DAQReadout() {
    154157
    155   delete EventService;
    156   delete[] DIMEventData;
     158  delete Command;
     159
     160  delete EventService;  delete[] DIMEventData;
    157161  delete RHeader;               delete EHeader;
    158162  delete HVFB;                  delete[] ACalibTemp;
     
    160164  delete[] DRSFreq;     delete[] BStruct;
    161165  delete[] WaveForm;    delete[] TriggerCell;
    162  
    163   // Destroy mutex
    164   if (pthread_mutex_destroy(&Mutex) != 0) State(ERROR, "pthread_mutex_destroy() failed");
     166
     167  delete ConsoleOut;
     168  free(ConsoleText);
     169 
     170  if (pthread_mutex_destroy(&Mutex) != 0) Message(ERROR, "pthread_mutex_destroy() failed");
    165171}
    166172
     
    171177void DAQReadout::Execute(char *Command) {
    172178
    173   if (strlen(Command)==0) return;  // Ignore empty commands
    174 
    175   if(Command[0]=='.') {   // Shell command
     179  if (Command[0]=='.') {   // Shell command
    176180    system(&(Command[1]));
    177181    return;
    178182  }
    179183
    180   for(int i=0; i<MAX_NUM_TOKEN; i++) Param[i] = "";  // All pointers point initially to empty string
     184  for (int i=0; i<MAX_NUM_TOKEN; i++) Param[i] = "";  // All pointers point initially to empty string
    181185  NParam = ParseInput(Command, Param);
    182 
    183   for(CmdNumber=0; CmdNumber<sizeof(CommandList)/sizeof(CL_Struct); CmdNumber++)
    184     if (Match(Param[0], CommandList[CmdNumber].Name)) {
    185       if(CommandList[CmdNumber].NeedNotBusy && daq_state==active) PrintMessage("DAQ is busy\n");
    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           }
    192       return; 
    193     }
    194   PrintMessage("Unknown command '%s'\n",Param[0]);
     186 
     187  // Search for command
     188  unsigned int Count;
     189  for (Count=0; Count<sizeof(CommandList)/sizeof(CL_Struct); Count++) {
     190    if (Match(Param[0], CommandList[Count].Name)) break;
     191  }
     192 
     193  // Command not found?
     194  if (Count == sizeof(CommandList)/sizeof(CL_Struct)) {
     195        PrintMessage("Unknown command '%s'\n", Param[0]);
     196        return;
     197  }
     198
     199  if(CommandList[Count].NeedNotBusy && daq_state==active) PrintMessage("DAQ is busy\n");
     200  else if(CommandList[Count].NeedNotBusy && NumBoards==0) PrintMessage("No boards available\n");
     201  else {
     202        int Ret;
     203
     204        // Lock (Execute() runs in thread spawned by commandHandler())
     205        if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
     206          Message(FATAL, "pthread_mutex_lock() failed (%s)", strerror(Ret));
     207        }
     208        // Run command
     209        CmdNumber = Count;
     210        (this->*CommandList[CmdNumber].CommandPointer)();
     211        // Unlock
     212        if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
     213          Message(FATAL, "pthread_mutex_unlock() failed (%s)", strerror(Ret));
     214        }
     215  }
    195216}
    196217         
     
    199220  time_t ActualT;
    200221  time (&ActualT);
    201   PrintMessage("%d:%02d:%02d\n", (int) difftime(ActualT, StartTime)/3600, ((int) difftime(ActualT, StartTime)/60)%60, (int) difftime(ActualT, StartTime)%60);
     222  PrintMessage("%02d:%02d:%02d\n", (int) difftime(ActualT, StartTime)/3600, ((int) difftime(ActualT, StartTime)/60)%60, (int) difftime(ActualT, StartTime)%60);
    202223}
    203224
     
    11161137  }
    11171138 
    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 
    1122   // First chunk: trigger cells
    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;
    1126 
    1127   // Remaining chunks: ADC data (two chucks per channel if wrap around of pipeline occurred)
     1139  // ADC data (two chucks per channel if wrap around of pipeline occurred, therefore
     1140  // IOV_MAX>=2 is checked at startup
    11281141  for (int i=FirstBoard; (i<=LastBoard + (NumBoards==0)); i++) {
    11291142    for (unsigned int k=0; k<RHeader->NChips; k++) {
     
    12021215void DAQReadout::DoPrintMessage(const char *Format, va_list ArgumentPointer, int Target) {
    12031216
    1204   static char Textbuffer[MAX_COM_SIZE];
    1205  
    1206   memset(Textbuffer, 0, sizeof(Textbuffer)); 
    1207   vsnprintf(Textbuffer, sizeof(Textbuffer), Format, ArgumentPointer);
     1217  static char Error[] = "vasprintf() failed in DoPrintMessage()";
     1218  char *Text;
     1219
     1220  // Evaluate arguments   
     1221  if (vasprintf(&Text, Format, ArgumentPointer) == -1) Text = Error;
    12081222 
    12091223  // Print to console
    12101224  if(Target & MsgToConsole) {
    1211     if(strlen(Textbuffer)>0 && Textbuffer[strlen(Textbuffer)-1]=='\n') {
    1212       printf("\r%s%s", Textbuffer, Prompt);   // New prompt
    1213     }
    1214     else printf("%s", Textbuffer);
     1225    if(strlen(Text)>0 && Text[strlen(Text)-1]=='\n') printf("\r%s%s", Text, Prompt);  // New prompt
     1226    else printf("%s", Text);
    12151227        fflush(stdout);
    12161228  }
    12171229 
    1218   // Send to DIM service
    1219   SetStdOut(Textbuffer);
    1220 
    1221   // Send to log
    1222   if(Target & MsgToLog) {
    1223     char *Buf;
    1224     if (asprintf(&Buf, "%s %s", SERVER_NAME, Textbuffer) != -1) {
    1225       DimClient::sendCommandNB("DColl/Log", Buf);
    1226       free(Buf);
    1227     }
    1228     else DimClient::sendCommandNB("DColl/Log", SERVER_NAME" asprintf() failed");
    1229   }
     1230  // Send to DIM console service and to log if requested
     1231  ConsoleOut->updateService(Text);
     1232  if(Target & MsgToLog) SendToLog("%s %s", SERVER_NAME, Text);
     1233
     1234  // Free old text
     1235  if (ConsoleText != Error) free(ConsoleText);
     1236  ConsoleText = Text;
    12301237}
    12311238
     
    12331240void DAQReadout::commandHandler() {
    12341241
    1235   // Copy command to new buffer (must be freed by the new thread)
     1242  // Ignore empty or illegal strings
     1243  if (getCommand()->getSize() == 0 ||
     1244          *((char *) getCommand()->getData()+getCommand()->getSize()-1) != '\0' ||
     1245          strlen(getCommand()->getString()) == 0) return;
     1246
     1247  // Copy command to new buffer (will be freed by global Execute() function)
    12361248  char *Command;
    1237   if (asprintf(&Command, "%s", getString()) == -1) {
     1249  if (asprintf(&Command, "%s", getCommand()->getString()) == -1) {
    12381250        PrintMessage("asprintf() failed in DRSReadout::commandHandler() (%s)\n", strerror(errno));
    12391251        return;
     
    13141326      else if (daq_runtype == pedestal) StopDRS();   // ..or for software trigger
    13151327
    1316       // Read event data
     1328      // Read event data and restart (reduces dead-time because waiting for next trigger while writing)
    13171329          ReadCalibratedDRSData();
    1318          
    1319           // Restart here reduces dead-time (already waiting for next trigger while writing)
    13201330          StartDRS();
    13211331
     
    13861396  else PrintMessage("\rRun #%d (%s) aborted due to error after %d events\n", RunNumber, daq_runtype_str[daq_runtype], NumEvents);
    13871397
    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 
    13921398  // Print run statistics
    13931399  if (NumEvents>0 && !WriteError) {
     
    14451451}
    14461452
     1453// Stub to call Execute() metho of class and free command memory
    14471454void Execute(char *Command) {
    14481455
  • drsdaq/DAQReadout.h

    r211 r226  
    3333enum runtype_enum {data, pedestal, reserved, test};
    3434
    35 class DAQReadout : public DRS, public DRSCallback, public DimCommand, public EvidenceServer {
     35class DAQReadout : public DRS, public DRSCallback, public EvidenceServer {
    3636
    37     time_t StartTime;
     37        time_t StartTime;
    3838        pid_t MainThread;
    3939        DimService *EventService;
    4040        int MinDelay;
    4141    unsigned int CmdNumber;
     42        DimCommand *Command;
     43        DimService *ConsoleOut;
     44        char *ConsoleText;
    4245
    4346    void PrintUsage();
  • drsdaq/HVFeedback.cc

    r211 r226  
    2525// Constructor: Initialise feedback
    2626//
    27 HVFeedback::HVFeedback(DAQReadout* DAQClass){//:
    28                         //EvidenceServer(SERVER_NAME){
     27HVFeedback::HVFeedback(DAQReadout* DAQClass){
    2928
    3029  m = DAQClass;
     
    139138  }
    140139 
    141   // Update DIM service regularly
     140  // Update DIM count service regularly
    142141  if (time(NULL)-LastServiceUpdate > 2) {
    143142    LastServiceUpdate = time(NULL);
     
    148147
    149148  // Feedback action
     149  std::stringstream Cmd;
     150 
    150151  for (i=m->FirstBoard; i<=m->LastBoard; i++) {
    151152  for (j=0; j<fNumberOfChips; j++) {
     
    165166
    166167                if(fabs(Average[i][j][k]) < 2*Sigma[i][j][k]) printf("Too noisy!\n");
    167                 else WriteHVCommand("hv %s %+f\n",PixMap->DRS_to_Pixel(i,j,k).c_str(), Correction);
    168 
     168                else {
     169                  Cmd << PixMap->DRS_to_Pixel(i,j,k)+" " << std::showpos << Correction << " ";
     170                }
    169171            break;
    170172
     
    175177          case FB_ResponseFirst:  // First point of response measurement done 
    176178            Buffer[i][j][k] = Average[i][j][k];
    177             if(!PixMap->DRS_to_Pixel(i,j,k).empty()) WriteHVCommand("hv %s %+f",PixMap->DRS_to_Pixel(i,j,k).c_str(), DiffVoltage);
     179            if(!PixMap->DRS_to_Pixel(i,j,k).empty()) {
     180                  Cmd << PixMap->DRS_to_Pixel(i,j,k) << " " << std::showpos << DiffVoltage << " ";               
     181                }
    178182            break;
    179183
     
    184188            }
    185189            else Response[i][j][k] = DiffVoltage/(Buffer[i][j][k]-Average[i][j][k]);
    186             if(!PixMap->DRS_to_Pixel(i,j,k).empty()) WriteHVCommand("hv %s %+f",PixMap->DRS_to_Pixel(i,j,k).c_str(), -DiffVoltage/2);
     190            if(!PixMap->DRS_to_Pixel(i,j,k).empty()) {
     191                  Cmd << PixMap->DRS_to_Pixel(i,j,k) << " " << std::showpos << -DiffVoltage/2 << " ";                             
     192                }
    187193            break;
    188194
     
    196202  FeedbackAverage->updateService();
    197203  FeedbackSigma->updateService();
     204
     205  // Send command
     206  if (!Cmd.str().empty()) {
     207        DimClient::sendCommand("Bias/Command", ("hv "+Cmd.str()).c_str());
     208  }
    198209
    199210  switch (FBMode) {
     
    269280  else {
    270281    FBMode = Mode;
    271         if (Mode != FB_ResponseFirst) m->State(m->INFO, "%s", FBState_Description[FBMode]);
    272         else m->State(m->INFO, "%s (voltage difference %.3f)", FBState_Description[FBMode], DiffVoltage);
     282        if (Mode != FB_ResponseFirst) m->Message(m->INFO, "%s", FBState_Description[FBMode]);
     283        else m->Message(m->INFO, "%s (voltage difference %.3f)", FBState_Description[FBMode], DiffVoltage);
    273284    ClearAverages();
    274285  }
     
    320331void HVFeedback::MeasureResponse(float U) {
    321332
     333  std::stringstream Cmd;
     334
    322335  if (U==0) {
    323336    m->PrintMessage("HV Feedback: Error, voltage difference must not non-zero.\n");
     
    325338  }
    326339
    327   for (int i=m->FirstBoard; i<=m->LastBoard; i++)
    328     for (int j=0; j<fNumberOfChips; j++)
    329       for (int k=0; k<fNumberOfChannels; k++) {
    330                 if(!PixMap->DRS_to_Pixel(i,j,k).empty()) {
    331           WriteHVCommand("hv %s %+f\n",PixMap->DRS_to_Pixel(i,j,k).c_str(), -U/2);
    332         }
    333       }
     340  for (int i=m->FirstBoard; i<=m->LastBoard; i++) {
     341  for (int j=0; j<fNumberOfChips; j++) {
     342  for (int k=0; k<fNumberOfChannels; k++) {
     343        if(!PixMap->DRS_to_Pixel(i,j,k).empty()) {
     344          Cmd << PixMap->DRS_to_Pixel(i,j,k) << " " << std::showpos << -U/2 << " ";                               
     345    }
     346  }
     347  }
     348  }
     349 
     350  // Send command
     351  if (!Cmd.str().empty()) {
     352        DimClient::sendCommand("Bias/Command", ("hv "+Cmd.str()).c_str());
     353  }
     354
    334355  DiffVoltage = U;
    335356  SetFBMode(FB_ResponseFirst, true);
     
    351372
    352373//
    353 // Write bias voltage commmand
    354 //
    355 bool HVFeedback::WriteHVCommand(const char *Format, ...) {
    356 
    357   char Textbuffer[MAX_COM_SIZE];
    358  
    359   va_list ArgumentPointer;  va_start(ArgumentPointer, Format);
    360   vsnprintf(Textbuffer, sizeof(Textbuffer), Format, ArgumentPointer);
    361 
    362   DimClient::sendCommand("Bias/Command", Textbuffer);
    363   return true;
    364 }
    365 
    366 //
    367374// Print feedback configuration
    368375//
  • drsdaq/HVFeedback.h

    r211 r226  
    66#include <stdlib.h>
    77#include <math.h>
     8#include <sstream>
    89
    910#include "RawDataCTX.h"
     
    1213enum FBState {FB_Off, FB_Active, FB_Targets, FB_ResponseFirst, FB_ResponseSecond};
    1314
    14 class HVFeedback: public DimServer {//EvidenceServer {
     15class HVFeedback: public DimServer {
    1516
    1617    class DAQReadout *m;
     
    7071    void GetResponse();
    7172    void ClearAverages();
    72     bool WriteHVCommand(const char *, ...);
    7373    void PrintConfig(int);
    7474};
  • drsdaq/drsdaq.cpp

    r211 r226  
    3636  int LockDescriptor;
    3737
    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   }
    46    
    4738  // Assure only one instance of program runs (lock creator written to log file)
    48   // Lock file deleted by ExitFunction()
     39  // Lock file deleted by destructor
    4940  if((LockDescriptor = open(LOCKFILE,O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)) == -1) {
    5041    if(errno==EEXIST) {
     
    5950  sprintf(str,"echo Created >%s; date >>%s; echo by $USER@$HOSTNAME >>%s",LOCKFILE,LOCKFILE,LOCKFILE);
    6051  system(str);
    61  
     52
     53  // Readline library uses getc() (allows interruption by signal)
     54  rl_getc_function = getc;
     55
     56  // writev() in DAQ thread needs to be able to write at least 3 chunks
     57  if(IOV_MAX < 2) {
     58        printf("Fatal error: IOV_MAX is less than 2, cannot use writev() to write event data.\n");
     59        exit(EXIT_FAILURE);
     60  }
     61     
    6262  system("clear");
    6363  printf("\n*** DRS readout (built %s, %s, revision %s) *** \n\n",__DATE__, __TIME__, REVISION);
     64
     65  // Set exit function
     66  atexit(&ExitFunction);
    6467
    6568  // Construct main instance (static ensures destructor is called with exit())
    6669  static DAQReadout M;
    6770
    68   // Set signal and exit handlers
    69   atexit(&ExitFunction);
     71  // Set signal handlers
    7072  signal(SIGILL, &CrashHandler);
    7173  signal(SIGABRT, &CrashHandler);
     
    8890    // Process command
    8991        DimClient::sendCommand(SERVER_NAME"/Command", Command);
    90 
    9192    free(Command);
    9293  } 
     
    9495
    9596
    96 //*****************
    97 //  Signal handlers
    98 //*****************
    99 
    10097// Remove lock file before running default signal code
    10198void CrashHandler(int Signal) {
    10299  remove(LOCKFILE);
    103   printf("Caught signal number %d. Removing lockfile and performing standard signal action. Good luck.\n",Signal);
     100  printf("Caught signal number %d. Removed lockfile and performing standard signal action. Good luck.\n",Signal);
    104101  signal(Signal, SIG_DFL);
    105102  raise(Signal);
     
    109106void ExitFunction() {
    110107
    111   if (remove(LOCKFILE)==-1) {
     108  if (remove(LOCKFILE) == -1) {
    112109    printf("Could not remove lock file %s (%s)\n", LOCKFILE, strerror(errno));
    113110  }
    114 
    115   return;         
    116111}
  • hvcontrol/History.txt

    r220 r226  
    118/7/2009    Changed path to pixelmap in ProcessIO.h to stay within repository
    22            Removed unused makefiles
    3             Moved config file to config directory of repository
    4             Removed writing of config file
    5             Removed several unused functions
    6             Removed command to switch off logging
     3                Moved config file to config directory of repository
     4                Removed writing of config file
     5                Removed several unused functions
     6                Removed command to switch off logging
    779/7/2009    Implemented readline library for command-line editing
    88            Included logging functions in main class (solved lockfile problem)
    9             Only a single log file is written
     9                Only a single log file is written
    101010/7/2009   Removed reference voltage related code (not supported by hardware)   
    111117/7/2009   Communication with FDTI now with Linux kernel driver (virtual com
    1212            port) instead of FTDI library (Standard open()/read()/write()
    13             system calls can be used).
     13                system calls can be used).
    141420/7/2009   Reading with time-out from tty uses now select()
    151522/7/2009   Combined code of 'hv' and 'hvdiff' commands. With either one, pixel id,
    1616            channel number of keyword 'all' can be used. Removed configuration
    17             option to set usage of DAC values. Instead, a third parameter 'dac'
    18             to the 'hv' and 'hvdiff' commands chooses DAC values.
     17                option to set usage of DAC values. Instead, a third parameter 'dac'
     18                to the 'hv' and 'hvdiff' commands chooses DAC values.
    191924/7/2009   Lockfile is deleted if configuration file cannot be read
    202027/7/2009   Slow data is written for every HV ramp to file given in configuration
     
    23233/8/2009    Removed explicit test mode. Commands 'hv' and 'hvdiff' will simply
    2424            return OK if no HV boards available.
    25             Number of HV boards is not limited anymore.
     25                Number of HV boards is not limited anymore.
    262624/9/2009   Program is terminated if too many errors are encountered by the
    2727            monitor thread
     
    353529/1/2010       DAC value 0 is now equivilant to calibrated voltage value 0
    36364/6/2010        Command 'hv' allows an array of pixel IDs/voltages (used by feedback)
     3715/6/2010       'Channels' now is counted continously from 0 to NUM_CHAINS*NUM_CHANNELS,
     38                        removed 'chain' command
  • hvcontrol/hvcontrol.cpp

    r183 r226  
    2323
    2424// Function prototypes
    25 void ConsoleCommand(ProcessIO *);
    2625void HVMonitor(ProcessIO *);
    2726void DummyHandler(int);
     
    3231//   Main program
    3332// ================
    34 //
    35 // Several unlikely system call failures are handled via throwing an exception.
    3633
    37 int main(int argc, char *argv[]) {
     34int main() {
    3835
    39   char str[MAX_COM_SIZE];
    40   pthread_t thread_ConsoleCommand,thread_HVMonitor;
     36  char str[MAX_COM_SIZE], *Command;
     37  pthread_t thread_HVMonitor;
    4138  int LockDescriptor;
    4239
     
    7269  atexit(&ExitFunction);
    7370 
    74   // Construct main instance and create mutex for thread synchronization
    75   ProcessIO pio;
    76   if (pthread_mutex_init(&pio.control_mutex, NULL) != 0) {
    77     perror("pthread_mutex_init failed");
    78     throw;
    79   }
     71  // Construct main instance
     72  static ProcessIO M;
    8073 
    8174  // These signals were set during construction of EvidenceServer
     
    8578  signal(SIGTERM, &CrashHandler);
    8679
    87   // Create threads
    88   if ((pthread_create(&thread_ConsoleCommand, NULL, (void * (*)(void *)) ConsoleCommand,(void *) &pio)) != 0) {
    89     perror("pthread_create failed with console thread");
    90     throw;
     80  // Create monitor thread and make accessible for sending signal
     81  if ((pthread_create(&thread_HVMonitor, NULL, (void * (*)(void *)) HVMonitor,(void *) &M)) != 0) {
     82    M.Message(M.FATAL, "pthread_create failed with HVMonitor thread");
    9183  }
    92   if ((pthread_create(&thread_HVMonitor, NULL, (void * (*)(void *)) HVMonitor,(void *) &pio)) != 0) {
    93     perror("pthread_create failed with HVMonitor thread");
    94     throw;
    95   }
     84  M.HVMonitor = thread_HVMonitor;
    9685
    97   // Threads should be accessible for sending signals
    98   pio.HVMonitor = thread_HVMonitor;
    99 
    100   // Wait for threads to quit
    101   pthread_join(thread_ConsoleCommand, NULL);
    102   pthread_join(thread_HVMonitor, NULL);
    103 
    104   // Destruct mutex and main instance
    105   pthread_mutex_destroy (&pio.control_mutex);
    106   pio.~ProcessIO();
    107 
    108   // Remove lockfile
    109   if (remove(LOCKFILE)==-1) {
    110     sprintf(str, "Could not remove lock file %s", LOCKFILE);
    111     perror(str);
    112     exit(EXIT_FAILURE);
    113   }
    114 
    115   exit(EXIT_SUCCESS);
    116 }
    117 
    118 
    119 /********************************************************************\
    120 
    121   ConsoleCommand thread
    122 
    123   Handle console input using readline library functions to allow
    124   line editing and history capability
    125 
    126 \********************************************************************/
    127 
    128 void ConsoleCommand(ProcessIO *m) {
    129 
    130   char *Command;
    131 
    132   while (!m->Exit) {
    133        
     86  while (!M.ExitRequest) {       
    13487    // Assemble prompt
    135     snprintf(m->Prompt, sizeof(m->Prompt),"\rHV");
    136     if (m->NumHVBoards == 0) sprintf(m->Prompt+strlen(m->Prompt),"> ");
     88    if (M.NumHVBoards == 0) snprintf(M.Prompt, sizeof(M.Prompt), "\rBias> ");
    13789    else {
    138       if (m->FirstChain == m->LastChain) sprintf(m->Prompt+strlen(m->Prompt),"|C%d",m->FirstChain);
    139       else sprintf(m->Prompt+strlen(m->Prompt),"|C%d-%d",m->FirstChain,m->LastChain);
    140 
    141       if (m->NumHVBoards == 0) sprintf(m->Prompt+strlen(m->Prompt),"> ");
    142       else if (m->FirstBoard == m->LastBoard) sprintf(m->Prompt+strlen(m->Prompt),"|B%d> ",m->FirstBoard);
    143       else snprintf(m->Prompt,sizeof(m->Prompt),"\rDAQ|B%d-%d> ",m->FirstBoard,m->LastBoard);
     90      if (M.FirstBoard == M.LastBoard) snprintf(M.Prompt, sizeof(M.Prompt), "\rBias|B%d> ",M.FirstBoard);
     91      else snprintf(M.Prompt, sizeof(M.Prompt),"\rBias|B%d-%d> ",M.FirstBoard, M.LastBoard);
    14492    }
    14593
    14694    // Read Command
    147     Command = readline(m->Prompt);
    148     if (Command==NULL) {
    149       m->PrintMessage("Error reading command line input\n");
    150       continue;
    151     }
     95    Command = readline(M.Prompt);
     96    if (Command == NULL) continue;
    15297    if(strlen(Command)>0) add_history(Command);
    15398
    154     // Process command (via DIM gives automatic serialisation)
     99    // Process command (via DIM gives automatic thread serialisation)
    155100        DimClient::sendCommand("Bias/Command", Command);
    156101    free(Command);
     102  }
     103
     104  // Wait for thread to quit
     105  if (pthread_join(thread_HVMonitor, NULL) != 0) {
     106    M.PrintMessage("pthread_join() failed in main()");
    157107  }
    158108}
     
    161111/********************************************************************\
    162112
    163   HVMonitor
    164 
    165113  Monitor HV board status
    166   Sebastian Commichau, November 2008
    167114
    168115\********************************************************************/
    169116
    170117void HVMonitor(ProcessIO *m) {
    171  
    172   while (!m->Exit) {
    173     if (m->state == active) {
    174       pthread_mutex_lock(&m->control_mutex);
    175       m->Monitor();
    176       pthread_mutex_unlock(&m->control_mutex); 
    177     }
     118
     119 
     120  while (!m->ExitRequest) {
     121    if (m->state == active) m->Monitor();
    178122    usleep((unsigned long)floor(1000000./(m->NumHVBoards*m->fStatusRefreshRate)));
    179123  }
     
    202146// This function will be implicitly called by exit()
    203147void ExitFunction() {
    204   remove(LOCKFILE);
    205   return;         
     148
     149  if (remove(LOCKFILE) == -1) {
     150    printf("Could not remove lock file %s (%s)\n", LOCKFILE, strerror(errno));
     151  }
    206152}
  • hvcontrol/src/ProcessIO.cc

    r220 r226  
    2222  } CommandList[] =
    2323   {{"board", &ProcessIO::cmd_board, 1, "<i>|<i j>|<all>" ,"Address board i, boards i-j or all boards or list boards"},
    24         {"chain", &ProcessIO::cmd_chain, 1, "<i>|<i> <j>|<all>","Address chain i, chains i-j or all chains"},
    25         {"hv", &ProcessIO::cmd_hv, 2, "<id>|<ch>|<all> <v>", "Change bias of pixel, ch. or all ch. of active chain(s)/board(s)"},
     24        {"hv", &ProcessIO::cmd_hv, 2, "<id>|<ch>|<all> <v>", "Change bias of pixel or (all) chan. of active boards"},
    2625        {"status", &ProcessIO::cmd_status, 0, "[dac]", "Show status information (DAC values if requested)"},
    2726        {"config", &ProcessIO::cmd_config, 0, "", "Print configuration"},
     
    4039using namespace std;
    4140
     41
     42// Constructor
    4243ProcessIO::ProcessIO(): EvidenceServer(SERVER_NAME) {
    4344
     
    4647
    4748  // Initialize status variables
    48   state     = active;
    49   Exit      = false;
    50  
     49  state       = active;
     50  ConsoleText = NULL;
     51
    5152  NumHVBoards = 0;
    5253  FirstBoard  = 0;
    5354  LastBoard   = -1;
    54   FirstChain  = 0;
    55   LastChain   = NUM_CHAINS-1;
     55
     56  // Initialize mutex for thread synchronisation
     57  if (pthread_mutex_init(&Mutex, NULL) != 0) {
     58    Message(FATAL, "pthread_mutex_init() failed");
     59  }
     60
     61  // DIM console service used in PrintMessage()
     62  ConsoleOut = new DimService(SERVER_NAME"/ConsoleOut", (char *) "");
    5663
    5764  // Get configuration data
     
    94101
    95102
     103// Destructor
    96104ProcessIO::~ProcessIO() {
    97105 
     
    101109  delete[] fHVBoard;
    102110   
    103   delete pm;        delete calib;
     111  delete pm;
     112  delete calib;
     113  delete ConsoleOut;   
     114  free(ConsoleText);
     115 
     116  // Destroy mutex
     117  if (pthread_mutex_destroy(&Mutex) != 0) Message(ERROR, "pthread_mutex_destroy() failed");
    104118}
    105119
     
    180194}
    181195
    182 // Adress chains
    183 void ProcessIO::cmd_chain() {
    184    
    185   if (!NumHVBoards) return;
    186 
    187   if (Match(Parameter[1],"all")) {
    188     FirstChain = 0;
    189     LastChain = 3;
    190   }
    191   else if (Parameter.size()==2 && atoi(Parameter[1].c_str())>=0 && atoi(Parameter[1].c_str())<NUM_CHAINS) {
    192     FirstChain = atoi(Parameter[1].c_str());
    193     LastChain = FirstChain;
    194   }
    195   else if (Parameter.size()==3 && atoi(Parameter[1].c_str())>=0 && atoi(Parameter[1].c_str())<NUM_CHAINS &&
    196          atoi(Parameter[2].c_str())>0 && atoi(Parameter[2].c_str())<NUM_CHAINS) {
    197     FirstChain = atoi(Parameter[1].c_str());
    198     LastChain = atoi(Parameter[2].c_str());
    199   }
    200   else PrintMessage("Cannot address chain(s), out of range.\n");
    201 }
    202196
    203197// Print configuration
     
    209203  for (int i=0; i<NumHVBoards; i++) PrintMessage(" Board %d: %s\n", i, fHVBoard[i]->BoardName);
    210204
    211   PrintMessage( " TimeOut:           %.2f s\n"
    212                 " StatusRefreshRate: %.2f Hz\n"
     205  PrintMessage( " StatusRefreshRate: %.2f Hz\n"
    213206                " DACMin value:      %d\n"
    214207                " DACMax value:      %d\n"
     
    216209                " HVCalibSlope :     %f\n"
    217210                " HVMaxDiff :        %u\n",
    218                 fTimeOut, fStatusRefreshRate, DACMin,
     211                fStatusRefreshRate, DACMin,
    219212                DACMax, fHVCalibOffset, fHVCalibSlope, fHVMaxDiff);
    220213}
     
    236229void ProcessIO::cmd_hv() {
    237230
    238   int hvoltage, DACValue, Errors=0, Board=-1, Chain=-1, Channel=-1;
    239   double hvoltageV;
     231  int Int, SingleChannel;
     232  unsigned int DACValue, Errors=0;
     233  double Double;
    240234  bool SetDac;
    241235
    242   // If array of channels, evaluate here (used by DIM)
    243   if (Parameter.size()>3 && pm->Pixel_to_HVboard(Parameter[3]) != 999999999) {
    244         for (unsigned int n=1; n<Parameter.size()-1; n+=2) {
    245           if (pm->Pixel_to_HVboard(Parameter[n]) != 999999999) {
    246         Board = pm->Pixel_to_HVboard(Parameter[n]);
    247         Chain = pm->Pixel_to_HVchain(Parameter[n]);
    248         Channel = pm->Pixel_to_HVchannel(Parameter[n]);
    249                 hvoltageV = atof(Parameter[n+1].c_str());
    250                 if (isdigit(Parameter[n+1][0])==0) fHVBoard[Board]->HVV[Chain][Channel] += hvoltageV;
    251             else fHVBoard[Board]->HVV[Chain][Channel] = hvoltageV;
    252             DACValue = calib->HVToDAC(fHVBoard[Board]->HVV[Chain][Channel], Board, Chain, Channel);
    253 
    254           }
    255         }       
    256     return;
    257   }
    258 
    259   // Evaluate voltage parameter
    260   if (Parameter.size()==4 && Match(Parameter[3], "dac")) {
    261     SetDac = true;
    262     if (!ConvertToInt(Parameter[2], &hvoltage)) {
    263       PrintMessage("Error: Wrong number format for DAC voltage setting\n");
    264       return;
    265     }
    266   }
    267   else {
    268     SetDac = false;
    269     if (!ConvertToDouble(Parameter[2], &hvoltageV)) {
    270       PrintMessage("Error: Wrong number format for voltage setting\n");
    271       return;
    272     }
    273   }
    274 
    275   // Evaluate pixel or channel parameter   
    276   if(pm->Pixel_to_HVboard(Parameter[1]) != 999999999) {
    277     Board = pm->Pixel_to_HVboard(Parameter[1]);
    278     Chain = pm->Pixel_to_HVchain(Parameter[1]);
    279     Channel = pm->Pixel_to_HVchannel(Parameter[1]);
    280   }
    281   else if (!Match(Parameter[1], "all") && !ConvertToInt(Parameter[1], &Channel)) {
    282     PrintMessage("Error: Wrong channel identification\n");
    283     return;
    284   }
    285 
     236  // Interpretation as DAC value requested?
     237  if (Parameter.size() == 4 && Match(Parameter[3], "dac")) SetDac = true;
     238  else SetDac = false;
     239
     240  // Interprete first number (might be channel number)
     241  if (!ConvertToInt(Parameter[1], &SingleChannel)) SingleChannel = -1;
     242
     243  // Loop over all boards
    286244  for (int i=FirstBoard; i<=LastBoard; i++) {
    287     if (i!=Board && Board!=-1) continue;
    288   for (int j=FirstChain; j<=LastChain; j++) {
    289       if (j!=Chain && Chain!=-1) continue;
    290   for (int k=0; k<NUM_CHANNELS; k++) {
    291         if (k!=Channel && Channel!=-1) continue;
    292 
    293         // Voltage change ignored if DAC value is zero
    294         if (isdigit(Parameter[2][0])==0 && fHVBoard[i]->HV[j][k] == 0) continue;
    295 
    296         // Determine new DAC values
    297         if (!SetDac){
    298           if (isdigit(Parameter[2][0])==0) fHVBoard[i]->HVV[j][k] += hvoltageV; // voltage change
    299           else fHVBoard[i]->HVV[j][k] = hvoltageV;
    300           DACValue = calib->HVToDAC(fHVBoard[i]->HVV[j][k], i, j, k);
    301         }
    302         else {
    303           if (isdigit(Parameter[2][0])==0) DACValue = fHVBoard[i]->HV[j][k] + hvoltage; // voltage change
    304           else DACValue = hvoltage;
    305         }
    306 
    307         // Set new voltage (if DAC value, update calibrated value)
    308         if (!RampVoltage(DACValue, i, j, k)) Errors++;
    309         if (SetDac) fHVBoard[i]->HVV[j][k] = calib->DACToHV(fHVBoard[i]->HV[j][k], i, j, k);
    310   } // Channels
    311   } // Chains
    312 
    313   // Update DIM service
    314   fHVBoard[i]->BiasVolt->updateService();
     245        // Loop over all channels given as command parameter
     246        for (unsigned int n=1; n<Parameter.size()-1; n+=2) {
     247          // Loop over all channels
     248          for (int j=0; j<NUM_CHAINS; j++) for (int k=0; k<NUM_CHANNELS; k++) {
     249
     250                // Current channel must be considered?
     251                if (!Match(Parameter[1], "all") && !(i == (int) pm->Pixel_to_HVboard(Parameter[n]) &&
     252                        j == (int) pm->Pixel_to_HVchain(Parameter[n]) && k == (int) pm->Pixel_to_HVchannel(Parameter[n])) &&
     253                        !(j == SingleChannel/NUM_CHANNELS && k == SingleChannel%NUM_CHANNELS)) continue;
     254
     255                // Voltage change (number starts with + oder -) ignored if current DAC value is zero
     256                if (isdigit(Parameter[n+1][0])==0 && fHVBoard[i]->HV[j][k] == 0) continue;
     257
     258                // Set new voltage/DAC value
     259                if (!SetDac){
     260                  // Convert voltage value and check format
     261                  if (!ConvertToDouble(Parameter[n+1], &Double)) {
     262                        PrintMessage("Error: Wrong number format for voltage setting\n");
     263                        goto LeaveLoop;
     264                  }
     265                  // Adjust voltage and DAV value
     266                  if (isdigit(Parameter[n+1][0]) == 0) fHVBoard[i]->HVV[j][k] += Double;
     267                  else fHVBoard[i]->HVV[j][k] = Double;
     268                  DACValue = calib->HVToDAC(fHVBoard[i]->HVV[j][k], i, j, k);
     269                }
     270                else {
     271                  // Convert DAC value and check format
     272                  if (!ConvertToInt(Parameter[n+1], &Int)) {
     273                        PrintMessage("Error: Wrong number format for DAC voltage setting\n");
     274                        goto LeaveLoop;
     275                  }
     276                  // Adjust DAC value
     277                  if (isdigit(Parameter[n+1][0]) == 0) DACValue = fHVBoard[i]->HV[j][k] + Int;
     278                  else DACValue = Int;
     279                }
     280
     281                // Set new voltage (if DAC value, update calibrated value)
     282                if (!RampVoltage(DACValue, i, j, k)) Errors++;
     283                if (SetDac) fHVBoard[i]->HVV[j][k] = calib->DACToHV(fHVBoard[i]->HV[j][k], i, j, k);
     284          } // Channels and chains     
     285        } // Loop over command argument
     286
     287        // Update DIM service for this boar
     288        LeaveLoop:
     289        fHVBoard[i]->BiasVolt->updateService();
    315290  } // Boards
    316 
     291 
    317292  if (Errors > 0) PrintMessage("Errors on %d channel(s) occurred\n", Errors);
    318293}
     
    454429  for (int i=FirstBoard; i<=LastBoard; i++) {
    455430    PrintMessage(" BOARD %d (%s)   Wrap counter: %s (%d)  Manual reset: %s\n    Time-out: %.2f s  Error count: %d\n\n",
    456   fHVBoard[i]->GetBoardNumber(), fHVBoard[i]->BoardName,
    457   fHVBoard[i]->WrapOK ? "ok":"error",
    458   fHVBoard[i]->LastWrapCount,
    459   fHVBoard[i]->ResetButton ? "yes" : "no",
    460   fHVBoard[i]->fTimeOut,
    461   fHVBoard[i]->ErrorCount);
    462 
    463     for (int j=FirstChain; j<=LastChain; j++) {
     431                fHVBoard[i]->GetBoardNumber(), fHVBoard[i]->BoardName,
     432                fHVBoard[i]->WrapOK ? "ok":"error",     fHVBoard[i]->LastWrapCount,
     433                fHVBoard[i]->ResetButton ? "yes" : "no", fHVBoard[i]->fTimeOut, fHVBoard[i]->ErrorCount);
     434
     435    for (int j=0; j<NUM_CHAINS; j++) {
    464436          PrintMessage("  CHAIN %d     Over-current: %s\n", j, fHVBoard[i]->Overcurrent[j] ? "yes" : "no");
    465           for (int k=0;k<4;k++) {
    466         PrintMessage("\r");
    467             for (int l=0;l<8;l++) {
    468                   if(Parameter.size() == 2) PrintMessage("%5d ",fHVBoard[i]->HV[j][k*8+l]);
    469           else PrintMessage("%#5.2f ",fHVBoard[i]->HVV[j][k*8+l]);
    470         }
    471             PrintMessage("\n");
    472           }
     437          for (int l=0; l<NUM_CHANNELS; l++) {
     438                if (l%8 == 0) PrintMessage("\r%3.1d:  ", j*NUM_CHANNELS+l);
     439                if (Parameter.size() == 2) PrintMessage("%5d ",fHVBoard[i]->HV[j][l]);
     440        else PrintMessage("%#5.2f ",fHVBoard[i]->HVV[j][l]);
     441                if (l%8 == 7) PrintMessage("\n");
     442      }
    473443    }
    474444  }
     
    508478void ProcessIO::cmd_exit() {
    509479
    510   Exit = true;
     480  ExitRequest = true;
    511481  pthread_kill(HVMonitor, SIGUSR1);
    512482}
     
    535505void ProcessIO::DoPrintMessage(const char *Format, va_list ArgumentPointer, MsgTarget Target) {
    536506
    537   static char Textbuffer[MAX_COM_SIZE]; // static because of DIM service
    538 
    539   memset(Textbuffer, 0, sizeof(Textbuffer)); 
    540   vsnprintf(Textbuffer, sizeof(Textbuffer), Format, ArgumentPointer);
     507  static char Error[] = "vasprintf() failed in DoPrintMessage()";
     508  char *Text;
     509
     510  // Evaluate arguments   
     511  if (vasprintf(&Text, Format, ArgumentPointer) == -1) Text = Error;
    541512 
    542513  // Print to console
    543514  if(Target & Console) {
    544     if(strlen(Textbuffer)>0 && Textbuffer[strlen(Textbuffer)-1]=='\n') {
    545       printf("\r%s%s", Textbuffer, Prompt);   // New prompt
    546     }
    547     else printf("%s", Textbuffer);
     515    if(strlen(Text)>0 && Text[strlen(Text)-1]=='\n') printf("\r%s%s", Text, Prompt); // New prompt
     516    else printf("%s", Text);
    548517    fflush(stdout);
    549518  }
    550519
    551   // Send to DIM service
    552   SetStdOut(Textbuffer);
    553 
    554   // Send to log
    555   if(Target & Log) {
    556     char *Buf;
    557     if (asprintf(&Buf, "%s %s", SERVER_NAME, Textbuffer) != -1) {
    558       DimClient::sendCommandNB("DColl/Log", Buf);
    559       free(Buf);
    560     }
    561     else DimClient::sendCommandNB("DColl/Log", SERVER_NAME" asprintf() failed");
    562   }
     520  // Send to DIM console service and log
     521  ConsoleOut->updateService(Text);
     522  if(Target & Log) SendToLog("%s %s", SERVER_NAME, Text);
     523
     524  // Free old text
     525  if (ConsoleText != Error) free(ConsoleText);
     526  ConsoleText = Text;
    563527}
    564528
     
    572536
    573537    if (fHVBoard[Board]->SetHV(Chain, Channel, fHVBoard[Board]->HV[Chain][Channel]+Diff) != 1) {
    574       State(ERROR, "Could not set bias of board %d, chain %d, channel %d. Skipping channel\n",fHVBoard[Board]->GetBoardNumber(),Chain,Channel);
     538      Message(ERROR, "Could not set bias of board %d, chain %d, channel %d. Skipping channel\n",fHVBoard[Board]->GetBoardNumber(),Chain,Channel);
    575539      return false;
    576540    }
     
    585549
    586550  static bool Warned = false;
    587  
     551  int Ret;
     552
     553  // Lock because command execution runs in different thread
     554  if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
     555        Message(FATAL, "pthread_mutex_lock() failed in commandHandler() (%s)", strerror(Ret));
     556  }
     557
    588558  for (int i=0; i<NumHVBoards; i++) {
    589559    if (fHVBoard[i]->ErrorCount > 10) {
     
    591561        Warned = true;
    592562        PrintMessage(All, "Warning: Some board has many read/write errors, status monitor disabled\n");
    593         State(WARN, "Warning: Some board has many read/write errors, status monitor disabled\n");
     563        Message(WARN, "Warning: Some board has many read/write errors, status monitor disabled\n");
    594564      }
    595565      continue;
     
    598568    if (fHVBoard[i]->GetStatus() != 1) {
    599569      PrintMessage(All, "Error: Monitor could not read status of board %d\n", fHVBoard[i]->GetBoardNumber());
    600       State(ERROR, "Error: Monitor could not read status of board %d\n", fHVBoard[i]->GetBoardNumber());
     570      Message(ERROR, "Error: Monitor could not read status of board %d\n", fHVBoard[i]->GetBoardNumber());
    601571    }
    602572   
    603573    if (fHVBoard[i]->ResetButton) {
    604574      PrintMessage(All, "Manual reset of board %d\n",fHVBoard[i]->GetBoardNumber());
    605       State(INFO, "Manual reset of board %d\n",fHVBoard[i]->GetBoardNumber());
     575      Message(INFO, "Manual reset of board %d\n",fHVBoard[i]->GetBoardNumber());
    606576      ResetBoard(i);
    607577    }
     
    609579    if (!fHVBoard[i]->WrapOK) {
    610580      PrintMessage(All, "Error: Wrap counter mismatch board %d\n",fHVBoard[i]->GetBoardNumber());
    611       State(ERROR, "Error: Wrap counter mismatch board %d\n",fHVBoard[i]->GetBoardNumber());
     581      Message(ERROR, "Error: Wrap counter mismatch board %d\n",fHVBoard[i]->GetBoardNumber());
    612582    }
    613583
     
    615585      if (fHVBoard[i]->Overcurrent[j]) {
    616586                PrintMessage(All, "Warning: Overcurrent in chain %d of board %d\n",j,fHVBoard[i]->GetBoardNumber());
    617                 State(WARN, "Warning: Overcurrent in chain %d of board %d\n",j,fHVBoard[i]->GetBoardNumber());
     587                Message(WARN, "Warning: Overcurrent in chain %d of board %d\n",j,fHVBoard[i]->GetBoardNumber());
    618588                ResetBoard(i);
    619589      }
    620590    }
    621591  }
     592 
     593  // Unlock
     594  if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
     595        Message(FATAL, "pthread_mutex_lock() failed in commandHandler() (%s)", strerror(Ret));
     596  }
     597
    622598}
    623599
     
    651627void ProcessIO::commandHandler() {
    652628
    653   pthread_mutex_lock(&control_mutex);
     629  int Ret;
     630
     631  if ((Ret = pthread_mutex_lock(&Mutex)) != 0) {
     632        Message(FATAL, "pthread_mutex_lock() failed in commandHandler() (%s)", strerror(Ret));
     633  }
     634
    654635  if (getCommand() == Command) CommandControl(getCommand()->getString());
    655   pthread_mutex_unlock(&control_mutex);
     636
     637  if ((Ret = pthread_mutex_unlock(&Mutex)) != 0) {
     638        Message(FATAL, "pthread_mutex_unlock() failed in commandHandler() (%s)", strerror(Ret));
     639  }
    656640}
    657641
  • hvcontrol/src/ProcessIO.h

    r220 r226  
    3333        PixelMap *pm;
    3434        DimCommand *Command;
     35        DimService *ConsoleOut;
     36        char *ConsoleText;
    3537
    3638        void commandHandler();
     
    3941        HVCalib     *calib;
    4042        HVBoard **fHVBoard;
    41 
    42         pthread_mutex_t control_mutex;
    4343
    4444        char Prompt[MAX_COM_SIZE];
     
    5757        // Status variables 
    5858        pthread_t HVMonitor;       // exit function sends signal to these threads
     59        pthread_mutex_t Mutex;
    5960
    6061        int NumHVBoards;
    6162        int FirstBoard;
    6263        int LastBoard;
    63         int FirstChain;
    64         int LastChain;
    65  
    6664        state_enum   state;
    67         bool Exit;
    6865
    6966        // Methods
     
    8784        void cmd_start();       void cmd_stop();
    8885        void cmd_uptime();      void cmd_help();
    89         void cmd_chain();
    9086};
    9187
Note: See TracChangeset for help on using the changeset viewer.