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 /***************************************************************
8 Sample plugout program to send the dataset (i,j,k)
9 indices for viewing.
10 ****************************************************************/
11
12 /***** Header file for communication routines *****/
13
14 #include "thd_iochan.h"
15 #include "niml.h"
16 #include "cs.h"
17 #include "afni_environ.h"
18
19 /***** Global variable determining on which system AFNI runs. *****/
20 /***** [default is the current system, can be changed by user] *****/
21
22 static char afni_host[128] = "." ;
23 static char afni_name[128] = "\0" ;
24 static int afni_port = 0 ; /* Init. before parsing command line
25 ZSS June 2011 */
26 static int afni_verbose = 0 ; /* print out debug info? */
27
28 /***** Prototype *****/
29
30 int afni_io(void) ;
31
32 /*===================================================================
33 Main program:
34 Read command line for options
35 Call afni_io routine forever
36 =====================================================================*/
37
main(int argc,char * argv[])38 int main( int argc , char * argv[] )
39 {
40 int narg , ii ;
41
42 (void)AFNI_prefilter_args(&argc,&argv);
43
44 afni_port = get_port_named("PLUGOUT_IJK_PORT"); /* ZSS June 2011 */
45
46 /***** See if the pitiful user wants help *****/
47
48 if( argc == 2 && strncmp(argv[1],"-help",5) == 0 ){
49 printf("Usage: plugout_ijk [-host name] [-v]\n"
50 "This program connects to AFNI and send (i,j,k)\n"
51 "dataset indices to control the viewpoint.\n\n"
52 "Options:\n"
53 " -host name Means to connect to AFNI running on the\n"
54 " computer 'name' using TCP/IP. The default is to\n"
55 " connect on the current host using shared memory.\n"
56 " -v Verbose mode.\n"
57 " -port pp Use TCP/IP port number 'pp'. The default is\n"
58 " %d, but if two plugouts are running on the\n"
59 " same computer, they must use different ports.\n"
60 " For a list of currently used ports use afni -list_ports\n"
61 " -name sss Use the string 'sss' for the name that AFNI assigns\n"
62 " to this plugout. The default is something stupid.\n"
63 "\n"
64 "To have different plugout_* programs talking to different\n"
65 "AFNI, use the -np* options below\n"
66 "%s\n"
67 , afni_port, get_np_help()) ;
68 exit(0) ;
69 }
70
71 /***** Process command line options *****/
72
73 narg = 1 ;
74 while( narg < argc ){
75
76 /** -host name **/
77
78 if( strncmp(argv[narg],"-host",5) == 0 ){
79 narg++ ;
80 if( narg >= argc ){
81 fprintf(stderr,"-host needs a following name!\a\n"); exit(1);
82 }
83 strcpy( afni_host , argv[narg] ) ;
84 narg++ ; continue ;
85 }
86
87 /** -name sss **/
88
89 if( strncmp(argv[narg],"-name",5) == 0 ){
90 narg++ ;
91 if( narg >= argc ){
92 fprintf(stderr,"-name needs a following string!\a\n"); exit(1);
93 }
94 strcpy( afni_name , argv[narg] ) ;
95 narg++ ; continue ;
96 }
97
98 /** -v **/
99
100 if( strncmp(argv[narg],"-v",2) == 0 ){
101 afni_verbose = 1 ;
102 narg++ ; continue ;
103 }
104
105 /** -port pp **/
106
107 if( strncmp(argv[narg],"-port",4) == 0 ){
108 narg++ ;
109 if( narg >= argc ){
110 fprintf(stderr,"-port needs a following argument!\a\n"); exit(1);
111 }
112 afni_port = strtol( argv[narg] , NULL , 10 ) ;
113 if( afni_port <= 0 ){
114 fprintf(stderr,"-port needs a positive argument!\a\n"); exit(1);
115 }
116 if( strcmp(afni_host,".") == 0 ) strcpy(afni_host,"localhost") ;
117 narg++ ; continue ;
118 }
119
120 /** Je ne sais pas **/
121
122 fprintf(stderr,"Unrecognized option: %s\a\n",argv[narg]) ;
123 exit(1) ;
124 }
125
126 /***** Loop and check in with AFNI every 100 msec *****/
127
128 while( 1 ){
129 ii = afni_io() ; /* commune with AFNI */
130 if( ii < 0 ) exit(0) ; /* bad trip? then die */
131 iochan_sleep(100) ; /* perchance to dream */
132 }
133
134 }
135
136 /*===================================================================
137 This routine handles all communications with AFNI.
138 The only input is the global variable afni_host, which determines
139 on which system AFNI is running.
140 The output is -1 if an error occured, 0 if everything is OK.
141 =====================================================================*/
142
143 /***** Mode flags for determining what afni_io does.
144 The routine progress through 5 stages:
145
146 1) Open a control connection to AFNI;
147 then
148 2) Wait until AFNI also opens the control connection;
149 then
150 3) Send a control string to AFNI saying what kind of
151 information we want, wait for an acknowledgment,
152 close the control connection, and open a data
153 connection to AFNI;
154 then
155 4) Wait for AFNI to also open the data connection;
156 then
157 5) Send data to AFNI! *****/
158
159 #define AFNI_OPEN_CONTROL_MODE 1 /* 1st time thru: open control channel */
160 #define AFNI_WAIT_CONTROL_MODE 2 /* wait for AFNI to open control chan */
161 #define AFNI_OPEN_DATA_MODE 3 /* now can open data channel to AFNI */
162 #define AFNI_WAIT_DATA_MODE 4 /* waiting for AFNI to open data chan */
163 #define AFNI_CONTINUE_MODE 5 /* at last! data channel is ready! */
164
165 /***** macros to send acknowledgement strings to AFNI *****/
166
167 #define POACKSIZE 4 /* length of acknowledgement strings */
168
169 #define PO_ACK_BAD(ic) iochan_sendall( (ic) , "BAD" , POACKSIZE )
170 #define PO_ACK_OK(ic) iochan_sendall( (ic) , "OK!" , POACKSIZE )
171 #define PO_SEND(ic,str) iochan_sendall( (ic) , (str) , strlen((str))+1 )
172
afni_io(void)173 int afni_io(void)
174 {
175 static int afni_mode = AFNI_OPEN_CONTROL_MODE ; /* status variable */
176 static IOCHAN * afni_ioc = NULL ; /* connection to AFNI */
177 int ii ;
178
179 /***************************************************************/
180 /***** Check to see if status is OK before we proceed. *****/
181 /***** (if an error occurs below, afni_mode gets set to 0) *****/
182
183 if( afni_mode <= 0 ) return -1 ;
184
185 /***********************************************************************/
186 /***** First time into this routine? Open control channel to AFNI *****/
187
188 if( afni_mode == AFNI_OPEN_CONTROL_MODE ){
189 char afni_iocname[128] ; /* will hold name of I/O channel */
190
191 /** Note that the control channel is always a
192 TCP/IP channel to port #get_port_named("AFNI_PLUGOUT_TCP_0")
193 (used to be #7955) on the AFNI host system **/
194
195 if( strcmp(afni_host,".") == 0 )
196 sprintf( afni_iocname , "tcp:%s:%d" ,
197 "localhost", get_port_named("AFNI_PLUGOUT_TCP_0") ); /* make name */
198 else
199 sprintf( afni_iocname , "tcp:%s:%d" ,
200 afni_host, get_port_named("AFNI_PLUGOUT_TCP_0") ) ; /* make name */
201
202 afni_ioc = iochan_init( afni_iocname , "create" ) ; /* create it */
203 if( afni_ioc == NULL ){
204 fprintf(stderr,
205 "Can't create control channel %s to AFNI!\n",afni_iocname) ;
206 afni_mode = 0 ;
207 return -1 ;
208 }
209 afni_mode = AFNI_WAIT_CONTROL_MODE ; /* waiting for AFNI connection */
210 if( afni_verbose )
211 fprintf(stderr,"AFNI control channel created\n") ;
212 }
213
214 /****************************************************/
215 /**** Check if AFNI control channel is connected ****/
216
217 if( afni_mode == AFNI_WAIT_CONTROL_MODE ){
218 ii = iochan_writecheck( afni_ioc , 5 ) ; /* wait at most 5 msec */
219
220 /** the iochan_*check() routines return
221 -1 for an error,
222 0 if not ready,
223 >0 if the I/O channel is ready. **/
224
225 if( ii < 0 ){
226 fprintf(stderr,"Control channel to AFNI failed!\a\n") ;
227 IOCHAN_CLOSE(afni_ioc) ;
228 afni_mode = 0 ;
229 return -1 ;
230 } else if( ii > 0 ){
231 afni_mode = AFNI_OPEN_DATA_MODE ; /* prepare to send data */
232 if( afni_verbose )
233 fprintf(stderr,"AFNI control channel connected\n");
234 } else {
235 return 0 ; /* try again next time */
236 }
237 }
238
239 /**********************************************************/
240 /**** Send control data to AFNI, and open data channel ****/
241
242 if( afni_mode == AFNI_OPEN_DATA_MODE ){
243 char afni_iocname[128] ;
244 char afni_buf[256] ;
245
246 /** decide name of data channel:
247 use shared memory (shm:) on ".",
248 use TCP/IP (tcp:) on other computer systems;
249 * Note that the TCP/IP port number can be
250 anything that isn't already in use;
251 * Note that the shm control name (here "test_plugout")
252 is a string that will be converted to an IPC
253 key (in function string_to_key in iochan.c). **/
254
255 if( strcmp(afni_host,".") == 0 )
256 strcpy( afni_iocname , "shm:test_plugout:1K+1K" ) ;
257 else
258 sprintf( afni_iocname , "tcp:%s:%d" , afni_host , afni_port ) ;
259
260 /** write the command to AFNI into the buffer:
261 * each command ends with a newline character,
262 except (possibly) the last command;
263 * the command buffer is a C string, which ends
264 with an ASCII NUL character;
265 * PONAME means 'use this string for informative messages';
266 * IOCHAN means 'use this I/O channel from now on'. **/
267
268 if( afni_name[0] == '\0' ) strcpy(afni_name,"aHorseCalledMan") ;
269
270 sprintf( afni_buf , "PONAME %s\n"
271 "IOCHAN %s" ,
272 afni_name , afni_iocname ) ;
273
274 if( afni_verbose )
275 fprintf(stderr,"Sending control information to AFNI\n") ;
276
277 /** note that the ASCII NUL at the end of the buffer is sent **/
278
279 ii = iochan_sendall( afni_ioc , afni_buf , strlen(afni_buf)+1 ) ;
280
281 /** the return value is the number of bytes sent,
282 or -1 indicating a fatal error transpired. **/
283
284 if( ii < 0 ){
285 fprintf(stderr,"Transmission of control data to AFNI failed!\a\n") ;
286 IOCHAN_CLOSE(afni_ioc) ;
287 afni_mode = 0 ;
288 return -1 ;
289
290 } else {
291
292 /** wait for the acknowledgment from AFNI, then close channel **/
293
294 ii = iochan_recvall( afni_ioc , afni_buf , POACKSIZE ) ;
295 IOCHAN_CLOSE(afni_ioc) ;
296
297 if( ii < 0 || strncmp(afni_buf,"OK!",3) != 0 ){
298 fprintf(stderr,"AFNI didn't like control information!\a\n") ;
299 afni_mode = 0 ;
300 return -1 ;
301 }
302
303 /** now open data channel to AFNI **/
304
305 afni_ioc = iochan_init( afni_iocname , "create" ) ;
306 if( afni_ioc == NULL ){
307 fprintf(stderr,
308 "Can't open data channel %s to AFNI!\a\n",afni_iocname) ;
309 afni_mode = 0 ;
310 return -1 ;
311 } else {
312 afni_mode = AFNI_WAIT_DATA_MODE ;
313 if( afni_verbose ) fprintf(stderr,"AFNI data channel created\n") ;
314 }
315 }
316 }
317
318 /****************************************************/
319 /***** See if data channel is connected to AFNI *****/
320
321 if( afni_mode == AFNI_WAIT_DATA_MODE ){
322
323 ii = iochan_goodcheck( afni_ioc , 5 ) ; /* wait at most 5 msec */
324 if( ii < 0 ){
325 fprintf(stderr,
326 "AFNI data channel aborted before any data was sent!\a\n") ;
327 IOCHAN_CLOSE( afni_ioc ) ;
328 afni_mode = 0 ;
329 return -1 ;
330 } else if( ii > 0 ){ /* ready to go! */
331 afni_mode = AFNI_CONTINUE_MODE ;
332 if( afni_verbose ) fprintf(stderr,"AFNI data channel is open\n") ;
333 } else {
334 return 0 ; /* try again next time */
335 }
336 }
337
338 /**************************************************************/
339 /***** The "normal" state of affairs: AFNI is connected. *****/
340 /***** See if the user wants to send i,j,k to AFNI. *****/
341
342 if( afni_mode == AFNI_CONTINUE_MODE ){
343 char afni_buf[256] ;
344 int ix , jy , kz ;
345
346 /* get user input */
347
348 printf("Enter i j k: ") ; fflush(stdout) ; afni_fgets(afni_buf,256,stdin) ;
349 ii = sscanf(afni_buf,"%d %d %d",&ix,&jy,&kz) ;
350 if( ii < 3 ){
351 printf("** Warning -- planetary meltdown will occur in 10 seconds!\a\n") ;
352 iochan_sleep(1000) ;
353 ii = iochan_writecheck(afni_ioc,5) ; if( ii < 0 ) return -1 ;
354 return 0 ;
355 }
356
357 /* send input to AFNI (essentially unedited) */
358
359 sprintf(afni_buf,"DSET_IJK_SET %d %d %d",ix,jy,kz) ;
360 ii = iochan_sendall( afni_ioc , afni_buf , strlen(afni_buf)+1 ) ;
361
362 if( ii > 0 ){ /* send was OK; wait for acknowledgment */
363 ii = iochan_recvall( afni_ioc , afni_buf , POACKSIZE ) ;
364 }
365
366 if( ii < 0 ){ /* send or acknowledgment failed */
367 fprintf(stderr,"AFNI data channel aborted!\a\n") ;
368 IOCHAN_CLOSE(afni_ioc) ;
369 afni_mode = 0 ;
370 return -1 ;
371 }
372 return 0 ;
373 }
374
375 return 0 ;
376 }
377