/**************************************************************\ Main program for the CTX G-APD HV supply, sends commands, reads and monitors status of the G-APD HV supply Sebastian Commichau, Sabrina Stark, Oliver Grimm \**************************************************************/ #include #include #include #include #include #include "ProcessIO.h" #include #include #define LOCKFILE "/tmp/CTX_HV_LOCK" // Function prototypes void ConsoleCommand(ProcessIO *); void HVMonitor(ProcessIO *); void DummyHandler(int); void CrashHandler(int); void ExitFunction(); // ================ // Main program // ================ // // Several unlikely system call failures are handled via throwing an exception. int main(int argc, char *argv[]) { char str[MAX_COM_SIZE]; pthread_t thread_ConsoleCommand,thread_HVMonitor; int LockDescriptor; // Assure only one instance of the HV control program runs // The flag O_EXCL together with O_CREAT assure that the lock // file cannot be opened by another instance, i.e. there are no parallel write accesses if((LockDescriptor = open(LOCKFILE,O_WRONLY|O_CREAT|O_EXCL,S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)) == -1) { if(errno==EEXIST) { printf("Error: Lock file already existing\n"); sprintf(str,"paste %s -s -d ' '",LOCKFILE); system(str); } else printf("Could not create lock file %s (%s)\n", LOCKFILE, strerror(errno)); exit(EXIT_FAILURE); } close(LockDescriptor); sprintf(str,"echo Created >%s; date >>%s; echo by $USER@$HOSTNAME>>%s",LOCKFILE,LOCKFILE,LOCKFILE); system(str); system("clear"); printf("\n*** Bias control (%s, %s, O. Grimm, S.Commichau, S.Stark) ***\n\n",__DATE__,__TIME__); // Install signal handler and set signal SIGUSR1 to interrupt blocking system calls signal(SIGUSR1, &DummyHandler); siginterrupt (SIGUSR1, true); // Assure lock file is deleted in case of a program crash or call to exit() signal(SIGILL, &CrashHandler); signal(SIGABRT, &CrashHandler); signal(SIGFPE, &CrashHandler); signal(SIGSEGV, &CrashHandler); signal(SIGBUS, &CrashHandler); atexit(&ExitFunction); // Construct main instance and create mutex for thread synchronization ProcessIO pio; if (pthread_mutex_init(&pio.control_mutex, NULL) != 0) { perror("pthread_mutex_init failed"); throw; } // These signals were set during construction of EvidenceServer signal(SIGQUIT, &CrashHandler); // CTRL-Backspace signal(SIGINT, &CrashHandler); // CTRL-C signal(SIGHUP, &CrashHandler); // Terminal closed signal(SIGTERM, &CrashHandler); // Create threads if ((pthread_create(&thread_ConsoleCommand, NULL, (void * (*)(void *)) ConsoleCommand,(void *) &pio)) != 0) { perror("pthread_create failed with console thread"); throw; } if ((pthread_create(&thread_HVMonitor, NULL, (void * (*)(void *)) HVMonitor,(void *) &pio)) != 0) { perror("pthread_create failed with HVMonitor thread"); throw; } // Threads should be accessible for sending signals pio.HVMonitor = thread_HVMonitor; // Wait for threads to quit pthread_join(thread_ConsoleCommand, NULL); pthread_join(thread_HVMonitor, NULL); // Destruct mutex and main instance pthread_mutex_destroy (&pio.control_mutex); pio.~ProcessIO(); // Remove lockfile if (remove(LOCKFILE)==-1) { sprintf(str, "Could not remove lock file %s", LOCKFILE); perror(str); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } /********************************************************************\ ConsoleCommand thread Handle console input using readline library functions to allow line editing and history capability \********************************************************************/ void ConsoleCommand(ProcessIO *m) { char *Command; while (!m->Exit) { // Assemble prompt snprintf(m->Prompt, sizeof(m->Prompt),"\rHV"); if (m->NumHVBoards == 0) sprintf(m->Prompt+strlen(m->Prompt),"> "); else { if (m->FirstChain == m->LastChain) sprintf(m->Prompt+strlen(m->Prompt),"|C%d",m->FirstChain); else sprintf(m->Prompt+strlen(m->Prompt),"|C%d-%d",m->FirstChain,m->LastChain); if (m->NumHVBoards == 0) sprintf(m->Prompt+strlen(m->Prompt),"> "); else if (m->FirstBoard == m->LastBoard) sprintf(m->Prompt+strlen(m->Prompt),"|B%d> ",m->FirstBoard); else snprintf(m->Prompt,sizeof(m->Prompt),"\rDAQ|B%d-%d> ",m->FirstBoard,m->LastBoard); } // Read Command Command = readline(m->Prompt); if (Command==NULL) { m->PrintMessage("Error reading command line input\n"); continue; } if(strlen(Command)>0) add_history(Command); // Process command (via DIM gives automatic serialisation) DimClient::sendCommand("Bias/Command", Command); free(Command); } } /********************************************************************\ HVMonitor Monitor HV board status Sebastian Commichau, November 2008 \********************************************************************/ void HVMonitor(ProcessIO *m) { while (!m->Exit) { if (m->state == active) { pthread_mutex_lock(&m->control_mutex); m->Monitor(); pthread_mutex_unlock(&m->control_mutex); } usleep((unsigned long)floor(1000000./(m->NumHVBoards*m->fStatusRefreshRate))); } } /********************************************************************\ Signal handlers \********************************************************************/ // Remove lock file before running default signal code void CrashHandler(int Signal) { remove(LOCKFILE); printf("Caught signal number %d. Removing lockfile and performing standard signal action. Good luck.\n",Signal); signal(Signal, SIG_DFL); raise(Signal); } // Dummy signal handler to return from blocking syscalls void DummyHandler(int Signal) { return; } // This function will be implicitly called by exit() void ExitFunction() { remove(LOCKFILE); return; }