source: drsdaq/drsdaq.cpp@ 60

Last change on this file since 60 was 55, checked in by ogrimm, 16 years ago
Config file reading updated, RawDataCTX class takes varying event size into account
File size: 8.9 KB
Line 
1/**************************************************************\
2
3 drsdaq.cpp
4
5 Main program for DRS CTX DAQ system. Global initialization,
6 starts threads for console input and socket interface.
7
8 Sebastian Commichau, Oliver Grimm
9
10\**************************************************************/
11
12#define DEFAULT_CONFIG "../config/DRSDAQ.conf" // Default configuration file
13#define LOCKFILE "/tmp/CT3_DAQ_LOCK"
14
15#include <stdio.h>
16#include <signal.h>
17#include <pthread.h>
18#include <sys/socket.h>
19#include <netdb.h>
20#include <arpa/inet.h>
21#include <readline/readline.h>
22#include <readline/history.h>
23
24#include "DAQReadout.h"
25#include "HVFeedback.h"
26
27// Function prototypes
28void ConsoleCommand(DAQReadout *);
29void CCCommand(DAQReadout *);
30void SignalHandler(int);
31void CrashHandler(int);
32
33// ================
34// Main program
35// ================
36//
37// Several unlikely system call failures are handled via throwing an exception.
38
39int main(int argc, char *argv[]) {
40
41 char str[MAX_COM_SIZE];
42 pthread_t thread_ConsoleCommand, thread_CCCommand;
43 int LockDescriptor;
44
45 // Interpret command line (do before lockfile creation in case of exit())
46 if((argc==3 && strcmp(argv[1],"-c")!=0) || argc==2) {
47 printf("Usage: %s [-c <ConfigFile>] Default file is \"%s\"\n", argv[0], DEFAULT_CONFIG);
48 exit(EXIT_SUCCESS);
49 }
50
51 // Assure only one instance of program runs (lock creator written to log file)
52 if((LockDescriptor = open(LOCKFILE,O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)) == -1) {
53 if(errno==EEXIST) {
54 printf("Error: Lock file already existing\n");
55 sprintf(str,"paste %s -s -d ' '",LOCKFILE);
56 system(str);
57 }
58 else printf("Could not create lock file %s (%s)\n", LOCKFILE, strerror(errno));
59 exit(EXIT_FAILURE);
60 }
61 close(LockDescriptor);
62 sprintf(str,"echo Created >%s; date >>%s; echo by $USER@$HOSTNAME >>%s",LOCKFILE,LOCKFILE,LOCKFILE);
63 system(str);
64
65 system("clear");
66 printf("\n*** DRS readout built %s, %s (revision %s) *** \n\n",__DATE__, __TIME__, REVISION);
67
68 // Set signal handlers
69 signal(SIGUSR1, &SignalHandler);
70 siginterrupt (SIGUSR1, true); // Set SIGUSR1 to interrupt (and not restart) blocking system calls
71 signal(SIGQUIT, &CrashHandler);
72 signal(SIGILL, &CrashHandler);
73 signal(SIGABRT, &CrashHandler);
74 signal(SIGFPE, &CrashHandler);
75 signal(SIGSEGV, &CrashHandler);
76 signal(SIGBUS, &CrashHandler);
77 signal(SIGTERM, &CrashHandler);
78 signal(SIGINT, &CrashHandler);
79 signal(SIGHUP, &CrashHandler);
80
81 // Construct main instance
82 DAQReadout dreadout(argc==3 ? argv[2] : DEFAULT_CONFIG);
83
84 // Create threads and mutex for thread synchronization
85 if (pthread_mutex_init(&dreadout.control_mutex, NULL) != 0) {
86 perror("pthread_mutex_init failed");
87 throw;
88 }
89 if ((pthread_create(&thread_ConsoleCommand, NULL, (void * (*)(void *)) ConsoleCommand,(void *) &dreadout)) != 0) {
90 perror("pthread_create failed with console thread");
91 throw;
92 }
93 if ((pthread_create(&thread_CCCommand, NULL, (void * (*)(void *)) CCCommand,(void *) &dreadout)) != 0) {
94 perror("pthread_create failed with socket thread");
95 dreadout.SocketThread = NULL;
96 }
97 else dreadout.SocketThread = &thread_CCCommand; // Thread should be accessible for sending signals
98
99 // Wait for threads to quit
100 pthread_join(thread_ConsoleCommand, NULL);
101 if(dreadout.SocketThread != NULL) pthread_join(thread_CCCommand, NULL);
102
103 // Destruct mutex and main instance
104 pthread_mutex_destroy (&dreadout.control_mutex);
105 dreadout.~DAQReadout();
106
107 // Remove lockfile
108 if (remove(LOCKFILE)==-1) {
109 printf("Could not remove lock file %s (%s)\n", LOCKFILE, strerror(errno));
110 exit(EXIT_FAILURE);
111 }
112 exit(EXIT_SUCCESS);
113}
114
115
116/********************************************************************\
117
118 ConsoleCommand thread
119
120 Handle console input using readline library functions to allow
121 line editing and history capability
122
123\********************************************************************/
124
125void ConsoleCommand(DAQReadout *m) {
126
127 time_t Time;
128 char *Command, Buf[MAX_COM_SIZE];;
129
130 while (!m->Exit) {
131 if (m->NumBoards == 0) snprintf(m->Prompt,sizeof(m->Prompt),"\rDAQ> ");
132 else if (m->FirstBoard == m->LastBoard) snprintf(m->Prompt,sizeof(m->Prompt),"\rDAQ|B%d> ",m->FirstBoard);
133 else snprintf(m->Prompt,sizeof(m->Prompt),"\rDAQ|B%d-%d> ",m->FirstBoard,m->LastBoard);
134
135 Command = readline(m->Prompt);
136 if (Command==NULL) {
137 m->PrintMessage("Error reading command line input\n");
138 continue;
139 }
140
141 if(strlen(Command)>0) add_history(Command);
142
143 strftime(Buf,MAX_COM_SIZE, "%d/%m/%y %X", localtime(&(Time=time(NULL))));
144 m->PrintMessage(MsgToLog, "CONSOLE(%s)> %s\n", Buf, Command);
145
146 // Process command
147 pthread_mutex_lock(&m->control_mutex);
148 m->CommandControl(Command);
149 pthread_mutex_unlock(&m->control_mutex);
150
151 free(Command);
152 }
153}
154
155
156
157/********************************************************************\
158
159 CCCommand thread
160
161 Listen to commands from socket (Central Control)
162
163 This thread will block execution in the accept() and read() socket function
164 while waiting for a connection or data. If the exit function is invoked through
165 keyboard command, these blocking functions are interrupted by raising the signal
166 SIGUSR1. Testing on errno=EINTR indicates this termination. The dummy signal
167 handler below is needed to prevent the standard thread termination occurring
168 when this signal is received.
169
170\********************************************************************/
171
172void CCCommand(DAQReadout *m) {
173
174 int ServerSocket,ConnectionSocket,ReadResult;
175 struct sockaddr_in SocketAddress, ClientAddress;
176 struct hostent *ClientName;
177 socklen_t SizeClientAddress=sizeof(ClientAddress);
178 char Command[MAX_COM_SIZE], Buf[MAX_COM_SIZE];
179 time_t Time;
180
181 // Set up server socket
182 if ((ServerSocket = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
183 m->PrintMessage("Could not open server socket, no remote connection possible (%s).\n", strerror(errno));
184 return;
185 }
186 // Allows immediate reuse of socket after closing (circumvents TIME_WAIT)
187 int Value=1;
188 if (setsockopt(ServerSocket, SOL_SOCKET, SO_REUSEADDR, (char *) &Value, sizeof (Value)) == -1) {
189 m->PrintMessage("Warning: Could not set server socket option SO_REUSEADDR (%s)\n", strerror(errno));
190 }
191
192 SocketAddress.sin_family = PF_INET;
193 SocketAddress.sin_port = htons((unsigned short) m->fCCPort);
194 SocketAddress.sin_addr.s_addr = INADDR_ANY;
195 if (bind(ServerSocket, (struct sockaddr *) &SocketAddress, sizeof(SocketAddress)) == -1)
196 {
197 m->PrintMessage("Could not bind port to socket (%s)\n", strerror(errno));
198 close(ServerSocket);
199 return;
200 }
201 if (listen(ServerSocket, 0) == -1) {
202 m->PrintMessage("Could not set socket to listening (%s)\n", strerror(errno));
203 close(ServerSocket);
204 return;
205 }
206
207 // Looping to wait for incoming connection
208 while (!m->Exit) {
209 if ((ConnectionSocket = accept(ServerSocket, (struct sockaddr *) &ClientAddress, &SizeClientAddress)) == -1) {
210 if (errno!=EINTR) m->PrintMessage("Failed to accept incoming connection (%s)\n", strerror(errno));
211 close(ServerSocket);
212 return;
213 }
214
215 ClientName = gethostbyaddr((char *) &ClientAddress.sin_addr ,sizeof(struct sockaddr_in),AF_INET);
216 m->PrintMessage("Connected to client at %s (%s).\n", inet_ntoa(ClientAddress.sin_addr), ClientName!=NULL ? ClientName->h_name:"name unknown");
217 m->Socket = ConnectionSocket;
218
219 while (!m->Exit) { // Looping as long as client exists
220 memset(Command,0,sizeof(Command));
221 ReadResult = read(ConnectionSocket, Command, MAX_COM_SIZE);
222 if (ReadResult==0) break; // Client not exisiting anymore
223 if (ReadResult==-1) {
224 if (errno!=EINTR) m->PrintMessage("Error read from socket (%s)\n", strerror(errno));
225 break;
226 }
227 if (Command[strlen(Command)-1]=='\n') Command[strlen(Command)-1]='\0'; // Remove trailing newline
228
229 strftime(Buf, MAX_COM_SIZE, "%d/%m/%y %X", localtime(&(Time=time(NULL))));
230 m->PrintMessage(MsgToConsole|MsgToLog, "SOCKET(%s)> %s\n", Buf, Command);
231
232 // Process command
233 pthread_mutex_lock(&m->control_mutex);
234 m->CmdFromSocket = true;
235 m->CommandControl(Command);
236 m->CmdFromSocket = false;
237 pthread_mutex_unlock(&m->control_mutex);
238 }
239 m->Socket = -1;
240 m->PrintMessage("Disconnected from client.\n");
241 close(ConnectionSocket);
242 }
243 close(ServerSocket);
244 m->PrintMessage("Server socket closed.\n");
245}
246
247
248/********************************************************************\
249
250 Signal handlers
251
252\********************************************************************/
253
254// Remove lock file before running default signal code
255void CrashHandler(int Signal) {
256 remove(LOCKFILE);
257 printf("Caught signal number %d. Removing lockfile and performing standard signal action. Good luck.\n",Signal);
258 signal(Signal, SIG_DFL);
259 raise(Signal);
260}
261
262// Dummy signal handler to return from blocking syscalls
263void SignalHandler(int Signal) {
264 return;
265}
Note: See TracBrowser for help on using the repository browser.