source: drsdaq/drsdaq.cpp@ 53

Last change on this file since 53 was 51, checked in by ogrimm, 17 years ago
Added command line editing
File size: 8.8 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", Buf, Command);
145
146 pthread_mutex_lock(&m->control_mutex);
147 m->CommandControl(Command, false);
148 pthread_mutex_unlock(&m->control_mutex);
149
150 free(Command);
151 }
152}
153
154
155
156/********************************************************************\
157
158 CCCommand thread
159
160 Listen to commands from socket (Central Control)
161
162 This thread will block execution in the accept() and read() socket function
163 while waiting for a connection or data. If the exit function is invoked through
164 keyboard command, these blocking functions are interrupted by raising the signal
165 SIGUSR1. Testing on errno=EINTR indicates this termination. The dummy signal
166 handler below is needed to prevent the standard thread termination occurring
167 when this signal is received.
168
169\********************************************************************/
170
171void CCCommand(DAQReadout *m) {
172
173 int ServerSocket,ConnectionSocket,ReadResult;
174 struct sockaddr_in SocketAddress, ClientAddress;
175 struct hostent *ClientName;
176 socklen_t SizeClientAddress=sizeof(ClientAddress);
177 char Command[MAX_COM_SIZE], Buf[MAX_COM_SIZE];
178 time_t Time;
179
180 // Set up server socket
181 if ((ServerSocket = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
182 m->PrintMessage("Could not open server socket, no remote connection possible (%s).\n", strerror(errno));
183 return;
184 }
185 // Allows immediate reuse of socket after closing (circumvents TIME_WAIT)
186 int Value=1;
187 if (setsockopt(ServerSocket, SOL_SOCKET, SO_REUSEADDR, (char *) &Value, sizeof (Value)) == -1) {
188 m->PrintMessage("Warning: Could not set server socket option SO_REUSEADDR (%s)\n", strerror(errno));
189 }
190
191 SocketAddress.sin_family = PF_INET;
192 SocketAddress.sin_port = htons((unsigned short) m->fCCPort);
193 SocketAddress.sin_addr.s_addr = INADDR_ANY;
194 if (bind(ServerSocket, (struct sockaddr *) &SocketAddress, sizeof(SocketAddress)) == -1)
195 {
196 m->PrintMessage("Could not bind port to socket (%s)\n", strerror(errno));
197 close(ServerSocket);
198 return;
199 }
200 if (listen(ServerSocket, 0) == -1) {
201 m->PrintMessage("Could not set socket to listening (%s)\n", strerror(errno));
202 close(ServerSocket);
203 return;
204 }
205
206 // Looping to wait for incoming connection
207 while (!m->Exit) {
208 if ((ConnectionSocket = accept(ServerSocket, (struct sockaddr *) &ClientAddress, &SizeClientAddress)) == -1) {
209 if (errno!=EINTR) m->PrintMessage("Failed to accept incoming connection (%s)\n", strerror(errno));
210 close(ServerSocket);
211 return;
212 }
213
214 ClientName = gethostbyaddr((char *) &ClientAddress.sin_addr ,sizeof(struct sockaddr_in),AF_INET);
215 m->PrintMessage("Connected to client at %s (%s).\n", inet_ntoa(ClientAddress.sin_addr), ClientName!=NULL ? ClientName->h_name:"name unknown");
216 m->Socket = ConnectionSocket;
217
218 while (!m->Exit) { // Looping as long as client exists
219 memset(Command,0,sizeof(Command));
220 ReadResult = read(ConnectionSocket, Command, MAX_COM_SIZE);
221 if (ReadResult==0) break; // Client not exisiting anymore
222 if (ReadResult==-1) {
223 if (errno!=EINTR) m->PrintMessage("Error read from socket (%s)\n", strerror(errno));
224 break;
225 }
226
227 strftime(Buf,MAX_COM_SIZE,"%d/%m/%y %X", localtime(&(Time=time(NULL))));
228 m->PrintMessage(MsgToLog,"SOCKET(%s)> %s%s",Buf, Command, Command[strlen(Command)-1]=='\n' ? "":"\n");
229 m->PrintMessage(MsgToConsole,"SOCKET> %s%s",Command, Command[strlen(Command)-1]=='\n' ? "":"\n");
230
231 pthread_mutex_lock(&m->control_mutex);
232 m->CommandControl(Command, true); // Process CC command
233 pthread_mutex_unlock(&m->control_mutex);
234 }
235 m->Socket = -1;
236 m->PrintMessage("Disconnected from client.\n");
237 close(ConnectionSocket);
238 }
239 close(ServerSocket);
240 m->PrintMessage("Server socket closed.\n");
241}
242
243
244/********************************************************************\
245
246 Signal handlers
247
248\********************************************************************/
249
250// Remove lock file before running default signal code
251void CrashHandler(int Signal) {
252 remove(LOCKFILE);
253 printf("Caught signal number %d. Removing lockfile and performing standard signal action. Good luck.\n",Signal);
254 signal(Signal, SIG_DFL);
255 raise(Signal);
256}
257
258// Dummy signal handler to return from blocking syscalls
259void SignalHandler(int Signal) {
260 return;
261}
Note: See TracBrowser for help on using the repository browser.