1 /*****************************************************************************
2 Major portions of this software are copyrighted by the Medical College
3 of Wisconsin, 1994-2000, and are released under the Gnu General Public
4 License, Version 2. See the file README.Copyright for details.
5 ******************************************************************************/
6
7 #include "def_epi.h"
8 #include "jp_afni.h"
9
10 EXT struct im_info imX[] ; /* the image data */
11
12 #if defined(AFNI_SIGNA_KECK)
13 extern int AJxres, AJreps, AJovs, AJtopovs, AJyres, epramp, opentry, oppos;
14 extern int opspf, opplane, opobplane, AJopte, opte2, opti, optr, opslquant;
15 extern float opfov, opslthick, opslspace, opnex, filt_band, sl_pos[];
16 extern int Signa_info ;
17 #endif
18
19 static char AFNI_infobuf[1024] = "\0" ; /* initialize to nothing */
20
21 /*--- 23 May 2001: allow for forking to send data to AFNI ---*/
22
23 #define USE_FORK /* turn this off to disable forkage */
24
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <signal.h>
28 #include <sys/wait.h>
29 static int use_fork = 0 ;
30 static pid_t pid_fork = 0 ;
31
32 /*****************************************************************************/
33
34 #include <signal.h>
35
AFNI_sigfunc(int sig)36 static void AFNI_sigfunc(int sig) /** signal handler for fatal errors **/
37 {
38 char * sname ;
39 switch(sig){
40 default: sname = "unknown" ; break ;
41 case SIGINT: sname = "SIGINT" ; break ;
42 case SIGPIPE: sname = "SIGPIPE" ; break ;
43 case SIGSEGV: sname = "SIGSEGV" ; break ;
44 case SIGBUS: sname = "SIGBUS" ; break ;
45 case SIGTERM: sname = "SIGTERM" ; break ;
46 }
47 fprintf(stderr,"\nFatal Signal %d (%s) received\n",sig,sname) ;
48 fprintf(stderr,"*** Program Abort ***\n") ; fflush(stderr) ;
49 exit(1) ;
50 }
51
52 /*****************************************************************************/
53
AFNI_exit(void)54 void AFNI_exit(void) /* Function to be called to make sure */
55 { /* the AFNI data channels get closed. */
56 iochan_close(AFNI_ioc) ;
57
58 #ifdef USE_FORK
59 if( use_fork && pid_fork != 0 && pid_fork != (pid_t)(-1) ){
60 int kk = kill( pid_fork , SIGTERM ) ;
61 if( kk == 0 ){
62 pid_t qpid=0 ;
63 for( kk=0 ; kk < 10 && qpid == 0 ; kk++ ){
64 iochan_sleep(5) ;
65 qpid = waitpid( pid_fork , NULL , WNOHANG ) ;
66 }
67 }
68 }
69 #endif
70
71 return ;
72 }
73
74 /*****************************************************************************
75 Do I/O startup stuff; nim images are in the imX buffer at this time.
76
77 At any given moment, this routine is in one of a number of modes
78 (the AFNI_mode variable).
79 The first time in, AFNI_mode == AFNI_OPEN_CONTROL_MODE. In each mode,
80 certain tasks must be accomplished and this program must be synchronized
81 with AFNI. When the necessary deeds are done, the routine advances to
82 the next mode. If the deeds cannot be done when this routine is called,
83 then it will stay in the same mode, and the next time it is called it
84 will try to do them again. This routine should be called repeatedly
85 until it progresses to the last mode (AFNI_CONTINUE_MODE), which is for
86 normal transmission of images (one at a time) to AFNI. This operation
87 is handled in the separate routine AFNI_send_image (infra).
88
89 If an error occurs, so that this program can no longer talk to AFNI, then
90 AFNI_mode is set to 0, which means "do nothing further". The rest of
91 the data acquisition software will continue, but these routines will
92 be stopped dead.
93 ******************************************************************************/
94
AFNI_start_io(int nim)95 void AFNI_start_io( int nim )
96 {
97 int ii ;
98
99 /***** Check for illegal conditions *****/
100
101 if( AFNI_mode <= 0 || AFNI_mode == AFNI_CONTINUE_MODE ) return ;
102
103 /***** If we are at the first time in,
104 try to open a control socket to talk to AFNI *****/
105
106 if( AFNI_mode == AFNI_OPEN_CONTROL_MODE ){
107
108 sprintf( AFNI_iochan , "tcp:%s:%d" ,
109 AFNI_host , get_port_named("AFNI_CONTROL_PORT")) ;
110
111 if( AFNI_verbose )
112 fprintf(stderr,"Opening control channel %s to AFNI.\n",AFNI_iochan) ;
113
114 AFNI_ioc = iochan_init( AFNI_iochan , "w" ) ;
115
116 if( AFNI_ioc == NULL ){
117 fprintf(stderr,"Can't open control channel %s to AFNI!\a\n",AFNI_iochan) ;
118 AFNI_mode = 0 ; return ;
119 } else {
120 if( AFNI_verbose ) fprintf(stderr,"Entering AFNI_WAIT_CONTROL_MODE.\n") ;
121 AFNI_mode = AFNI_WAIT_CONTROL_MODE ; /* begin waiting for AFNI connection */
122 }
123
124 signal( SIGTERM , AFNI_sigfunc ) ; /* 23 May 2001 */
125 signal( SIGSEGV , AFNI_sigfunc ) ;
126 signal( SIGINT , AFNI_sigfunc ) ;
127 }
128
129 /***** Check if the control socket is connected to AFNI *****/
130
131 if( AFNI_mode == AFNI_WAIT_CONTROL_MODE ){
132
133 ii = iochan_writecheck( AFNI_ioc , 1 ) ; /* Check; wait at most 1 msec */
134
135 /** if ii == 0, then the channel is still pending,
136 so do nothing; otherwise, take some action. **/
137
138 if( ii < 0 ){
139 fprintf(stderr,"Control channel to AFNI failed!\a\n") ;
140 IOCHAN_CLOSE(AFNI_ioc) ;
141 AFNI_mode = 0 ; return ;
142 } else if( ii > 0 ){
143 if( AFNI_verbose ) fprintf(stderr,"Control channel connected to AFNI."
144 " Entering AFNI_OPEN_DATA_MODE.\n") ;
145 AFNI_mode = AFNI_OPEN_DATA_MODE ; /* prepare to send data to AFNI */
146 }
147 }
148
149 /***** Send the control information, which says
150 how we will talk to AFNI in the future (shmem or TCP/IP),
151 then close the control channel and open this new data channel *****/
152
153 if( AFNI_mode == AFNI_OPEN_DATA_MODE ){
154
155 /** decide name of data channel: it can be TCP/IP or shared memory **/
156
157 if( AFNI_use_tcp ) sprintf(AFNI_iochan,"tcp:%s:%d",
158 AFNI_host,get_port_named("AFNI_TCP_PORT")) ;
159 else strcpy(AFNI_iochan,"shm:eps:8M") ;
160
161 strcpy(AFNI_buf,AFNI_iochan) ; /* tell AFNI where to read data */
162 if( AFNI_infocom[0] != '\0' ){
163 strcat(AFNI_buf,"\n") ;
164 strcat(AFNI_buf,AFNI_infocom) ; /* tell it where to get 3T info */
165 }
166
167 if( AFNI_verbose )
168 fprintf(stderr,"Sending control information to AFNI:\n%s\n",AFNI_buf) ;
169
170 ii = iochan_sendall( AFNI_ioc , AFNI_buf , strlen(AFNI_buf)+1 ) ;
171
172 /** A negative return is bad news **/
173
174 if( ii < 0 ){
175 fprintf(stderr,"Transmission of control data to AFNI failed!\a\n") ;
176 IOCHAN_CLOSE(AFNI_ioc) ;
177 AFNI_mode = 0 ; return ;
178 } else {
179 while( ! iochan_clearcheck(AFNI_ioc,2) ) /* wait for control data to clear */
180 iochan_sleep(2) ;
181 IOCHAN_CLOSE(AFNI_ioc) ; /* close control channel */
182
183 if( AFNI_verbose )
184 fprintf(stderr,"Opening data channel %s to AFNI.\n",AFNI_iochan) ;
185
186 #ifdef USE_FORK
187 use_fork = AFNI_use_tcp ;
188 #endif
189
190 if( use_fork ){ /* fork a relay process to talk to AFNI */
191
192 AFNI_ioc = iochan_init( "shm:forkage:8M" , "create" ) ;
193 if( AFNI_ioc == NULL ){
194 fprintf(stderr,"Can't open shm:forkage:8M for relay to AFNI!\n");
195 use_fork = 0 ; AFNI_mode = 0 ; return ;
196 }
197 pid_fork = iochan_fork_relay( "shm:forkage:8M" , AFNI_iochan ) ;
198 if( pid_fork == (pid_t)(-1) || pid_fork == 0 ){
199 fprintf(stderr,"Can't fork for relay to AFNI!\n") ;
200 IOCHAN_CLOSE(AFNI_ioc) ; pid_fork = 0 ; use_fork = 0 ;
201 AFNI_mode = 0 ; return ;
202 }
203
204 } else { /* directly handle I/O to AFNI ourselves */
205
206 AFNI_ioc = iochan_init( AFNI_iochan , "w" ) ; /* open data channel */
207 if( AFNI_ioc == NULL ){
208 fprintf(stderr,"Can't open data channel %s to AFNI!\a\n",AFNI_iochan) ;
209 AFNI_mode = 0 ; return ;
210 }
211 }
212
213 if( AFNI_verbose ) fprintf(stderr,"Entering AFNI_CATCHUP_MODE.\n") ;
214 AFNI_mode = AFNI_CATCHUP_MODE ;
215 }
216 }
217
218 /***** Wait for the data channel to be connected to AFNI,
219 and then send any images that are reconstructed and ready to go *****/
220
221 if( AFNI_mode == AFNI_CATCHUP_MODE ){
222
223 ii = iochan_writecheck( AFNI_ioc , 1 ) ; /* wait at most 1 msec */
224 if( ii < 0 ){
225 fprintf(stderr,"AFNI data channel aborted before any data was sent!\a\n") ;
226 IOCHAN_CLOSE( AFNI_ioc ) ;
227 use_fork = 0 ; AFNI_mode = 0 ; return ;
228 } else if( ii > 0 ){ /* can now send data to AFNI! */
229 if( AFNI_verbose )
230 fprintf(stderr,"AFNI data channel %s is connected.\n",AFNI_iochan) ;
231
232 /*** final preparation code depends on which scanner we are using ***/
233
234 #if defined(AFNI_BRUKER_BRI)
235
236 /*-- for the Bruker, don't need to check anything else
237 (external information comes from program 3T_toafni) --*/
238
239 if( AFNI_verbose )
240 fprintf(stderr,"Entering AFNI_CONTINUE_MODE.\n") ;
241 AFNI_mode = AFNI_CONTINUE_MODE ;
242
243 #elif defined(AFNI_SIGNA_KECK)
244
245 /*-- for the Keck Signa, we must have the external information now --*/
246
247 if( !Signa_info ){
248 double tt = COX_clock_time() ;
249
250 fprintf(stderr,
251 "\n\a"
252 "*** WARNING: Reading Signa info for AFNI ('load')\n");
253
254 read_Signa_cvs() ;
255
256 if( !Signa_info ){ /* failed! */
257 fprintf(stderr,
258 "\n\a"
259 "*** ERROR: Signa info is not 'load'-ed!\n"
260 "*** Closing connection to AFNI.\n") ;
261
262 IOCHAN_CLOSE( AFNI_ioc ) ;
263 use_fork = 0 ; AFNI_mode = 0 ; return ;
264 }
265
266 tt = COX_clock_time() - tt ;
267 fprintf(stderr,
268 "*** Signa info transferred in %.1f s\n",tt) ;
269 }
270
271 /*-- have external info, so compose it into the AFNI format --*/
272
273 /* info that never changes (at least yet) */
274
275 ii = strlen(AFNI_infobuf) ;
276 sprintf( AFNI_infobuf+ii , "ZORDER alt\n"
277 "ACQUISITION_TYPE 2D+zt\n" ) ;
278
279 /* field of view */
280
281 ii = strlen(AFNI_infobuf) ;
282 sprintf( AFNI_infobuf+ii , "XYFOV %.2f 0 0\n" , opfov ) ;
283
284 /* number of slices */
285
286 ii = strlen(AFNI_infobuf) ;
287 sprintf( AFNI_infobuf+ii , "ZNUM %d\n" , opslquant ) ;
288
289 /* slice thickness */
290
291 ii = strlen(AFNI_infobuf) ;
292 sprintf( AFNI_infobuf+ii , "ZDELTA %.2f\n" , opslthick+opslspace ) ;
293
294 /* slice orientation and offset */
295
296 { static char *zzz[3]={"S","R","A"} ; /* positive z-axis for each orientation */
297 char *axx , *ayy , *azz ; /* strings for each axis orientation */
298 int jj = opplane ; /* orientation code from Signa */
299
300 if( jj < 1 || jj > 3 ){
301 static char * pn[3] = { "Axial" , "Sagittal" , "Coronal" } ;
302 jj = opobplane ; if( jj < 1 || jj > 3 ) jj = 1 ;
303 fprintf(stderr,
304 "\n\a"
305 "*** WARNING: oblique slices; AFNI orientation=%s\n",pn[jj-1]) ;
306 }
307
308 /* 07 Mar 2000: modified some of these codes, per Lloyd Estkowski */
309
310 axx = ayy = azz = "???" ; /* just to keep the compiler happy */
311 switch( jj ){
312 case 1: /* Axial */
313 if( opspf == 0 ){ axx = "A-P" ; ayy = "R-L" ; }
314 else { axx = "L-R" ; ayy = "A-P" ; }
315
316 if( sl_pos[0] < sl_pos[1] ) azz = "I-S" ;
317 else azz = "S-I" ;
318 break ;
319
320 case 2: /* Sagittal */
321 if( opspf == 0 ){ axx = "S-I" ; ayy = "A-P" ; }
322 else { axx = "P-A" ; ayy = "S-I" ; }
323
324 if( sl_pos[0] < sl_pos[1] ) azz = "L-R" ;
325 else azz = "R-L" ;
326 break ;
327
328 case 3: /* Coronal */
329 if( opspf == 0 ){ axx = "I-S" ; ayy = "R-L" ; }
330 else { axx = "R-L" ; ayy = "S-I" ; }
331
332 if( sl_pos[0] < sl_pos[1] ) azz = "P-A" ;
333 else azz = "A-P" ;
334 break ;
335 }
336
337 ii = strlen(AFNI_infobuf) ;
338 sprintf( AFNI_infobuf+ii , "XYZAXES %s %s %s\n" , axx,ayy,azz ) ;
339
340 fprintf(stderr,"AFNI Signa info: plane=%d spf=%d\n" ,jj,opspf) ; /* debugging */
341 fprintf(stderr," => XYZAXES %s %s %s\n",axx,ayy,azz) ;
342 fprintf(stderr," => ZFIRST %.2f%s\n" ,sl_pos[0],zzz[jj-1] ) ;
343
344 ii = strlen(AFNI_infobuf) ;
345 sprintf( AFNI_infobuf+ii , "ZFIRST %.2f%s\n" , sl_pos[0],zzz[jj-1] ) ;
346 }
347
348 /* repetition time */
349
350 ii = strlen(AFNI_infobuf) ;
351 sprintf( AFNI_infobuf+ii , "TR %.3f\n" , 1.e-6*optr ) ;
352
353 /* ready to rock-n-roll */
354
355 if( AFNI_verbose )
356 fprintf(stderr,"Entering AFNI_CONTINUE_MODE.\n") ;
357 AFNI_mode = AFNI_CONTINUE_MODE ;
358
359 #endif /*** end of scanner dependent preparation code ***/
360
361 /*** if there are any images already accumulated, send them now! ***/
362
363 if( AFNI_mode == AFNI_CONTINUE_MODE ){
364 if( nim > 0 && AFNI_verbose )
365 fprintf(stderr,"Playing AFNI catchup with %d images.\n",nim) ;
366
367 for( ii=0 ; ii < nim ; ii++ ) AFNI_send_image( ii ) ;
368 }
369 }
370 }
371
372 return ;
373 }
374
375 /*******************************************************************************/
376
377 /** send image in imX[nim] to AFNI **/
378
AFNI_send_image(int nim)379 void AFNI_send_image( int nim )
380 {
381 int lx = imX[nim].x , ly = imX[nim].y , nbytes = 2*lx*ly , soff , jj ;
382
383 if( AFNI_mode != AFNI_CONTINUE_MODE ) return ;
384
385 if ( (lx*ly) == 65536 ) soff = OFFSET; /* for Signa */
386 else soff = 0;
387
388 /** before very 1st image, send data type and matrix size **/
389
390 if( nim == 0 ){
391
392 if( AFNI_verbose ) fprintf(stderr,"Sending 1st info+image to AFNI.\n") ;
393
394 if( AFNI_infobuf[0] == '\0' )
395 sprintf( AFNI_buf , "DATUM short\nXYMATRIX %d %d\n" , lx,ly ) ;
396 else
397 sprintf( AFNI_buf , "%s\nDATUM short\nXYMATRIX %d %d\n" ,
398 AFNI_infobuf , lx,ly ) ;
399
400 iochan_sendall( AFNI_ioc , AFNI_buf , strlen(AFNI_buf)+1 ) ;
401
402 } else if( AFNI_verbose ){
403
404 fprintf(stderr,"Sending image %d to AFNI.\n",nim+1) ;
405
406 }
407
408 jj = iochan_writecheck( AFNI_ioc , 1 ) ;
409 if( jj <= 0 ){
410 fprintf(stderr,"Image transmission to AFNI impossible at #%d.\a\n",nim) ;
411 if( AFNI_ioc->type == SHM_IOCHAN )
412 fprintf(stderr," shm: bstart=%d bend=%d\n",
413 *(AFNI_ioc->bstart),*(AFNI_ioc->bend) ) ;
414 iochan_sleep(1) ;
415 IOCHAN_CLOSE(AFNI_ioc) ;
416 use_fork = 0 ; AFNI_mode = 0 ;
417 fprintf(stderr,"Closed connection to AFNI\n") ;
418 return ;
419 }
420 if( AFNI_ioc->type == SHM_IOCHAN && jj < nbytes ){
421 fprintf(stderr,"Image transmission to AFNI incomplete at #%d.\a\n",nim) ;
422 if( AFNI_ioc->type == SHM_IOCHAN )
423 fprintf(stderr," shm: bstart=%d bend=%d\n",
424 *(AFNI_ioc->bstart),*(AFNI_ioc->bend) ) ;
425 iochan_sleep(1) ;
426 IOCHAN_CLOSE(AFNI_ioc) ;
427 use_fork = 0 ; AFNI_mode = 0 ;
428 fprintf(stderr,"Closed connection to AFNI\n") ;
429 return ;
430 }
431
432 jj = iochan_sendall( AFNI_ioc , imX[nim].arr + soff , nbytes ) ;
433
434 /** if the data channel failed, stop **/
435
436 if( jj < 0 ){
437 fprintf(stderr,"Image transmission to AFNI fails at #%d.\a\n",nim) ;
438 if( AFNI_ioc->type == SHM_IOCHAN )
439 fprintf(stderr," shm: bstart=%d bend=%d\n",
440 *(AFNI_ioc->bstart),*(AFNI_ioc->bend) ) ;
441 iochan_sleep(1) ;
442 IOCHAN_CLOSE(AFNI_ioc) ;
443 use_fork = 0 ; AFNI_mode = 0 ;
444 fprintf(stderr,"Closed connection to AFNI\n") ;
445 return ;
446 }
447
448 return ;
449 }
450