source: drsdaq/drsdaq.cpp@ 79

Last change on this file since 79 was 63, checked in by ogrimm, 15 years ago
Trigger cells stored in event data, data rotation no in memory but at disk transfer
File size: 9.1 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
88 DAQReadout dreadout(argc==3 ? argv[2] : DEFAULT_CONFIG);
89
90 // Create threads and mutex for thread synchronization
91 if (pthread_mutex_init(&dreadout.control_mutex, NULL) != 0) {
92 perror("pthread_mutex_init failed");
93 throw;
94 }
95 if ((pthread_create(&thread_ConsoleCommand, NULL, (void * (*)(void *)) ConsoleCommand,(void *) &dreadout)) != 0) {
96 perror("pthread_create failed with console thread");
97 throw;
98 }
99 if ((pthread_create(&thread_CCCommand, NULL, (void * (*)(void *)) CCCommand,(void *) &dreadout)) != 0) {
100 perror("pthread_create failed with socket thread");
101 dreadout.SocketThread = NULL;
102 }
103 else dreadout.SocketThread = &thread_CCCommand; // Thread should be accessible for sending signals
104
105 // Wait for threads to quit
106 pthread_join(thread_ConsoleCommand, NULL);
107 if(dreadout.SocketThread != NULL) pthread_join(thread_CCCommand, NULL);
108
109 // Destruct mutex and main instance
110 pthread_mutex_destroy (&dreadout.control_mutex);
111 dreadout.~DAQReadout();
112
113 // Remove lockfile
114 if (remove(LOCKFILE)==-1) {
115 printf("Could not remove lock file %s (%s)\n", LOCKFILE, strerror(errno));
116 exit(EXIT_FAILURE);
117 }
118 exit(EXIT_SUCCESS);
119}
120
121
122/********************************************************************\
123
124 ConsoleCommand thread
125
126 Handle console input using readline library functions to allow
127 line editing and history capability
128
129\********************************************************************/
130
131void ConsoleCommand(DAQReadout *m) {
132
133 time_t Time;
134 char *Command, Buf[MAX_COM_SIZE];;
135
136 while (!m->Exit) {
137 if (m->NumBoards == 0) snprintf(m->Prompt,sizeof(m->Prompt),"\rDAQ> ");
138 else if (m->FirstBoard == m->LastBoard) snprintf(m->Prompt,sizeof(m->Prompt),"\rDAQ|B%d> ",m->FirstBoard);
139 else snprintf(m->Prompt,sizeof(m->Prompt),"\rDAQ|B%d-%d> ",m->FirstBoard,m->LastBoard);
140
141 Command = readline(m->Prompt);
142 if (Command==NULL) {
143 m->PrintMessage("Error reading command line input\n");
144 continue;
145 }
146
147 if(strlen(Command)>0) add_history(Command);
148
149 strftime(Buf,MAX_COM_SIZE, "%d/%m/%y %X", localtime(&(Time=time(NULL))));
150 m->PrintMessage(MsgToLog, "CONSOLE(%s)> %s\n", Buf, Command);
151
152 // Process command
153 pthread_mutex_lock(&m->control_mutex);
154 m->CommandControl(Command);
155 pthread_mutex_unlock(&m->control_mutex);
156
157 free(Command);
158 }
159}
160
161
162
163/********************************************************************\
164
165 CCCommand thread
166
167 Listen to commands from socket (Central Control)
168
169 This thread will block execution in the accept() and read() socket function
170 while waiting for a connection or data. If the exit function is invoked through
171 keyboard command, these blocking functions are interrupted by raising the signal
172 SIGUSR1. Testing on errno=EINTR indicates this termination. The dummy signal
173 handler below is needed to prevent the standard thread termination occurring
174 when this signal is received.
175
176\********************************************************************/
177
178void CCCommand(DAQReadout *m) {
179
180 int ServerSocket,ConnectionSocket,ReadResult;
181 struct sockaddr_in SocketAddress, ClientAddress;
182 struct hostent *ClientName;
183 socklen_t SizeClientAddress=sizeof(ClientAddress);
184 char Command[MAX_COM_SIZE], Buf[MAX_COM_SIZE];
185 time_t Time;
186
187 // Set up server socket
188 if ((ServerSocket = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
189 m->PrintMessage("Could not open server socket, no remote connection possible (%s).\n", strerror(errno));
190 return;
191 }
192 // Allows immediate reuse of socket after closing (circumvents TIME_WAIT)
193 int Value=1;
194 if (setsockopt(ServerSocket, SOL_SOCKET, SO_REUSEADDR, (char *) &Value, sizeof (Value)) == -1) {
195 m->PrintMessage("Warning: Could not set server socket option SO_REUSEADDR (%s)\n", strerror(errno));
196 }
197
198 SocketAddress.sin_family = PF_INET;
199 SocketAddress.sin_port = htons((unsigned short) m->fCCPort);
200 SocketAddress.sin_addr.s_addr = INADDR_ANY;
201 if (bind(ServerSocket, (struct sockaddr *) &SocketAddress, sizeof(SocketAddress)) == -1)
202 {
203 m->PrintMessage("Could not bind port to socket (%s)\n", strerror(errno));
204 close(ServerSocket);
205 return;
206 }
207 if (listen(ServerSocket, 0) == -1) {
208 m->PrintMessage("Could not set socket to listening (%s)\n", strerror(errno));
209 close(ServerSocket);
210 return;
211 }
212
213 // Looping to wait for incoming connection
214 while (!m->Exit) {
215 if ((ConnectionSocket = accept(ServerSocket, (struct sockaddr *) &ClientAddress, &SizeClientAddress)) == -1) {
216 if (errno!=EINTR) m->PrintMessage("Failed to accept incoming connection (%s)\n", strerror(errno));
217 close(ServerSocket);
218 return;
219 }
220
221 ClientName = gethostbyaddr((char *) &ClientAddress.sin_addr ,sizeof(struct sockaddr_in),AF_INET);
222 m->PrintMessage("Connected to client at %s (%s).\n", inet_ntoa(ClientAddress.sin_addr), ClientName!=NULL ? ClientName->h_name:"name unknown");
223 m->Socket = ConnectionSocket;
224
225 while (!m->Exit) { // Looping as long as client exists
226 memset(Command,0,sizeof(Command));
227 ReadResult = read(ConnectionSocket, Command, MAX_COM_SIZE);
228 if (ReadResult==0) break; // Client not exisiting anymore
229 if (ReadResult==-1) {
230 if (errno!=EINTR) m->PrintMessage("Error read from socket (%s)\n", strerror(errno));
231 break;
232 }
233 if (Command[strlen(Command)-1]=='\n') Command[strlen(Command)-1]='\0'; // Remove trailing newline
234
235 strftime(Buf, MAX_COM_SIZE, "%d/%m/%y %X", localtime(&(Time=time(NULL))));
236 m->PrintMessage(MsgToConsole|MsgToLog, "SOCKET(%s)> %s\n", Buf, Command);
237
238 // Process command
239 pthread_mutex_lock(&m->control_mutex);
240 m->CmdFromSocket = true;
241 m->CommandControl(Command);
242 m->CmdFromSocket = false;
243 pthread_mutex_unlock(&m->control_mutex);
244 }
245 m->Socket = -1;
246 m->PrintMessage("Disconnected from client.\n");
247 close(ConnectionSocket);
248 }
249 close(ServerSocket);
250 m->PrintMessage("Server socket closed.\n");
251}
252
253
254/********************************************************************\
255
256 Signal handlers
257
258\********************************************************************/
259
260// Remove lock file before running default signal code
261void CrashHandler(int Signal) {
262 remove(LOCKFILE);
263 printf("Caught signal number %d. Removing lockfile and performing standard signal action. Good luck.\n",Signal);
264 signal(Signal, SIG_DFL);
265 raise(Signal);
266}
267
268// Dummy signal handler to return from blocking syscalls
269void SignalHandler(int Signal) {
270 return;
271}
Note: See TracBrowser for help on using the repository browser.