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