source: drsdaq/drsdaq.cpp@ 177

Last change on this file since 177 was 110, checked in by ogrimm, 15 years ago
DAQ can run without writing data to disk, bug fix to RawDataCTX reading routine
File size: 9.4 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 // writev() in DAQ thread needs to be able to write at least 3 chunks
46 if(IOV_MAX < 3) {
47 printf("Fatal error: IOV_MAX is less than 3, cannot use writev() to write event data.\n");
48 exit(EXIT_FAILURE);
49 }
50
51 // Interpret command line (do before lockfile creation in case of exit())
52 if((argc==3 && strcmp(argv[1],"-c")!=0) || argc==2) {
53 printf("Usage: %s [-c <ConfigFile>] Default file is \"%s\"\n", argv[0], DEFAULT_CONFIG);
54 exit(EXIT_SUCCESS);
55 }
56
57 // Assure only one instance of program runs (lock creator written to log file)
58 if((LockDescriptor = open(LOCKFILE,O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)) == -1) {
59 if(errno==EEXIST) {
60 printf("Error: Lock file already existing\n");
61 sprintf(str,"paste %s -s -d ' '",LOCKFILE);
62 system(str);
63 }
64 else printf("Could not create lock file %s (%s)\n", LOCKFILE, strerror(errno));
65 exit(EXIT_FAILURE);
66 }
67 close(LockDescriptor);
68 sprintf(str,"echo Created >%s; date >>%s; echo by $USER@$HOSTNAME >>%s",LOCKFILE,LOCKFILE,LOCKFILE);
69 system(str);
70
71 system("clear");
72 printf("\n*** DRS readout built %s, %s (revision %s) *** \n\n",__DATE__, __TIME__, REVISION);
73
74 // Set signal handlers
75 signal(SIGUSR1, &SignalHandler);
76 siginterrupt (SIGUSR1, true); // Set SIGUSR1 to interrupt (and not restart) blocking system calls
77 signal(SIGQUIT, &CrashHandler);
78 signal(SIGILL, &CrashHandler);
79 signal(SIGABRT, &CrashHandler);
80 signal(SIGFPE, &CrashHandler);
81 signal(SIGSEGV, &CrashHandler);
82 signal(SIGBUS, &CrashHandler);
83 signal(SIGTERM, &CrashHandler);
84 signal(SIGINT, &CrashHandler);
85 signal(SIGHUP, &CrashHandler);
86
87 // Construct main instance and create mutex for thread synchronization
88 DAQReadout dreadout(argc==3 ? argv[2] : DEFAULT_CONFIG);
89 if (pthread_mutex_init(&dreadout.control_mutex, NULL) != 0) {
90 perror("pthread_mutex_init failed");
91 throw;
92 }
93
94 if (dreadout.ConfigOK) { // Normal program execution only if configuration was complete
95 // Create threads
96 if (pthread_mutex_init(&dreadout.control_mutex, NULL) != 0) {
97 perror("pthread_mutex_init failed");
98 throw;
99 }
100 if ((pthread_create(&thread_ConsoleCommand, NULL, (void * (*)(void *)) ConsoleCommand,(void *) &dreadout)) != 0) {
101 perror("pthread_create failed with console thread");
102 throw;
103 }
104 if ((pthread_create(&thread_CCCommand, NULL, (void * (*)(void *)) CCCommand,(void *) &dreadout)) != 0) {
105 perror("pthread_create failed with socket thread");
106 dreadout.SocketThread = NULL;
107 }
108 else dreadout.SocketThread = &thread_CCCommand; // Thread should be accessible for sending signals
109
110 // Wait for threads to quit
111 pthread_join(thread_ConsoleCommand, NULL);
112 if(dreadout.SocketThread != NULL) pthread_join(thread_CCCommand, NULL);
113 }
114 else printf("Error: Configuration parameter missing in %s, terminating.\n", argc==3 ? argv[2] : DEFAULT_CONFIG);
115
116 // Destruct mutex and main instance
117 pthread_mutex_destroy (&dreadout.control_mutex);
118 dreadout.~DAQReadout();
119
120 // Remove lockfile
121 if (remove(LOCKFILE)==-1) {
122 printf("Could not remove lock file %s (%s)\n", LOCKFILE, strerror(errno));
123 exit(EXIT_FAILURE);
124 }
125 exit(EXIT_SUCCESS);
126}
127
128
129/********************************************************************\
130
131 ConsoleCommand thread
132
133 Handle console input using readline library functions to allow
134 line editing and history capability
135
136\********************************************************************/
137
138void ConsoleCommand(DAQReadout *m) {
139
140 char *Command;
141
142 while (!m->Exit) {
143
144 // Assemble prompt
145 if (m->NumBoards == 0) snprintf(m->Prompt,sizeof(m->Prompt),"\rDAQ> ");
146 else if (m->FirstBoard == m->LastBoard) snprintf(m->Prompt,sizeof(m->Prompt),"\rDAQ|B%d> ",m->FirstBoard);
147 else snprintf(m->Prompt,sizeof(m->Prompt),"\rDAQ|B%d-%d> ",m->FirstBoard,m->LastBoard);
148
149 // Read Command
150 Command = readline(m->Prompt);
151 if (Command == NULL) {
152 m->PrintMessage("Error reading command line input\n");
153 continue;
154 }
155 if(strlen(Command)>0) add_history(Command);
156
157 // Log command
158 m->PrintMessage(MsgToLog, "CONSOLE> %s\n", Command);
159
160 // Process command
161 pthread_mutex_lock(&m->control_mutex);
162 m->CommandControl(Command);
163 pthread_mutex_unlock(&m->control_mutex);
164
165 free(Command);
166 }
167}
168
169
170
171/********************************************************************\
172
173 CCCommand thread
174
175 Listen to commands from socket (Central Control)
176
177 This thread will block execution in the accept() and read() socket function
178 while waiting for a connection or data. If the exit function is invoked through
179 keyboard command, these blocking functions are interrupted by raising the signal
180 SIGUSR1. Testing on errno=EINTR indicates this termination. The dummy signal
181 handler below is needed to prevent the standard thread termination occurring
182 when this signal is received.
183
184\********************************************************************/
185
186void CCCommand(DAQReadout *m) {
187
188 int ServerSocket,ConnectionSocket,ReadResult;
189 struct sockaddr_in SocketAddress, ClientAddress;
190 struct hostent *ClientName;
191 socklen_t SizeClientAddress=sizeof(ClientAddress);
192 char Command[MAX_COM_SIZE];
193
194 // Set up server socket
195 if ((ServerSocket = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
196 m->PrintMessage("Could not open server socket, no remote connection possible (%s).\n", strerror(errno));
197 return;
198 }
199 // Allows immediate reuse of socket after closing (circumvents TIME_WAIT)
200 int Value=1;
201 if (setsockopt(ServerSocket, SOL_SOCKET, SO_REUSEADDR, (char *) &Value, sizeof (Value)) == -1) {
202 m->PrintMessage("Warning: Could not set server socket option SO_REUSEADDR (%s)\n", strerror(errno));
203 }
204
205 SocketAddress.sin_family = PF_INET;
206 SocketAddress.sin_port = htons((unsigned short) m->fCCPort);
207 SocketAddress.sin_addr.s_addr = INADDR_ANY;
208
209 if (bind(ServerSocket, (struct sockaddr *) &SocketAddress, sizeof(SocketAddress)) == -1)
210 {
211 m->PrintMessage("Could not bind port to socket (%s)\n", strerror(errno));
212 close(ServerSocket);
213 return;
214 }
215 if (listen(ServerSocket, 0) == -1) {
216 m->PrintMessage("Could not set socket to listening (%s)\n", strerror(errno));
217 close(ServerSocket);
218 return;
219 }
220
221 // Looping to wait for incoming connection
222 while (!m->Exit) {
223 if ((ConnectionSocket = accept(ServerSocket, (struct sockaddr *) &ClientAddress, &SizeClientAddress)) == -1) {
224 if (errno!=EINTR) m->PrintMessage("Failed to accept incoming connection (%s)\n", strerror(errno));
225 close(ServerSocket);
226 return;
227 }
228
229 ClientName = gethostbyaddr((char *) &ClientAddress.sin_addr ,sizeof(struct sockaddr_in),AF_INET);
230 m->PrintMessage("Connected to client at %s (%s).\n", inet_ntoa(ClientAddress.sin_addr), ClientName!=NULL ? ClientName->h_name:"name unknown");
231 m->Socket = ConnectionSocket;
232
233 // Looping as long as client exists and program not terminated
234 while (!m->Exit) {
235
236 // Try to read command from socket
237 memset(Command,0,sizeof(Command));
238 ReadResult = read(ConnectionSocket, Command, MAX_COM_SIZE);
239 if (ReadResult==0) break; // Client not exisiting anymore
240 if (ReadResult==-1) {
241 if (errno!=EINTR) m->PrintMessage("Error read from socket (%s)\n", strerror(errno));
242 break;
243 }
244 if (Command[strlen(Command)-1]=='\n') Command[strlen(Command)-1]='\0'; // Remove trailing newline
245
246 // Log command
247 m->PrintMessage(MsgToConsole|MsgToLog, "SOCKET> %s\n", Command);
248
249 // Process command
250 pthread_mutex_lock(&m->control_mutex);
251 m->CmdFromSocket = true;
252 m->CommandControl(Command);
253 m->CmdFromSocket = false;
254 pthread_mutex_unlock(&m->control_mutex);
255 }
256
257 m->Socket = -1;
258 m->PrintMessage("Disconnected from client.\n");
259 close(ConnectionSocket);
260 }
261 close(ServerSocket);
262 m->PrintMessage("Server socket closed.\n");
263}
264
265
266/********************************************************************\
267
268 Signal handlers
269
270\********************************************************************/
271
272// Remove lock file before running default signal code
273void CrashHandler(int Signal) {
274 remove(LOCKFILE);
275 printf("Caught signal number %d. Removing lockfile and performing standard signal action. Good luck.\n",Signal);
276 signal(Signal, SIG_DFL);
277 raise(Signal);
278}
279
280// Dummy signal handler to return from blocking syscalls
281void SignalHandler(int Signal) {
282 return;
283}
Note: See TracBrowser for help on using the repository browser.