## How to Program Realtime AFNI

The AFNI realtime plugin will assemble reconstructed slices or volumes into a 3D or 3D+time dataset. It does not do image reconstruction itself, but requires an image source. This is the documentation on how to write such an image source program.

## Sample Program

The program `rtfeedme.c` (part of the AFNI source code distribution) will take a pre-existing AFNI dataset, take it apart, and transmit it to the realtime plugin for reassembly and other processing. This software can be used as a starting point for development of a new program.

Using rtfeedme with AFNI
This simulation of realtime acquisition was written largely for testing purposes. The steps to use it are:

1. Start AFNI with the command
   `afni -rt`
   (the `-rt` switch enables the realtime plugin).
2. Use the `Datamode->Plugins` menu to start the `RT Options` plugin, which lets you control how various things happen during realtime acquisition.
3. Choose an existing dataset (say `fred+orig`), and send it to AFNI with the command
   `rfteedme -dt 30 fred+orig`

rtfeedme is not compiled by default with the rest of the AFNI package; if you have acquired the source code package, then you can compile this program with the command `make rtfeedme` .

## Hosts that AFNI Trusts

If you want to try using rtfeedme from a different system, and send data across the network, the command to do this would be
`rfteedme -dt 30 -hostname afnicomputername fred+orig`
However, AFNI won't accept a TCP/IP connection from just anyone.

AFNI checks the incoming IP address of socket connections to see if the host is on the "trust list". The default trust list is

       127.0.0.1 = localhost
    192.168   = private class B networks (this is a reserved set of
                   addresses that should not be visible to the Internet)

You can add to this list by defining the environment variable as in the example below (before starting AFNI):

      setenv AFNI_TRUSTHOST 123.45.67

This means that any IP address starting with the above string will be acceptable. If you want to add more than one possibility, then you can also use environment variables `AFNI_TRUSTHOST_1`, `AFNI_TRUSTHOST_2`, up to `AFNI_TRUSTHOST_99`. (That should be enough - how trusting do you really want to be?) You can also use hostnames (but not network names) in a `AFNI_TRUSTHOST` environment variable, but the IP address method is surer to work.

A number of other environment variables can control how the realtime plugin operates. See the text file README.environment for the details.

## Structure of a Realtime Image Source

There are several steps that an image source must take to get the communications with AFNI established:

1. Open the Control Channel
   The only information that is sent down the control channel is the description of how the actual data will be transmitted (i.e., describe the data channel). After this is done, the control channel should be closed by the image source.
2. Open the Data Channel
   This is the communication pathway that will be used to send image data and metadata from the image source program to AFNI.
   - N.B.: The control and data channels are one-way. They only send bytes to AFNI; no data is transmitted backwards to the image source. (However, the image source should detect if the control channel or data channel is closed abnormally, to be able to recover from the unlikely event of an AFNI crash.)
3. Send Image Metadata
   This information describes the format of the images that are about to be sent.
4. Send Image Data
   This is done as much as desired. When the data channel is broken, AFNI will write the new dataset to disk.
   - After the image metadata is sent, AFNI reads data in chunks of a whole image (2D or 3D, depending on `ACQUISITION_TYPE`). If the image source program sends only part of an image, then AFNI will freeze, waiting for the rest of that image's data bytes. The only exception this rule is if the image source does something to close the data channel (e.g., crashes). Note that if the image source computer itself crashes, AFNI may not be notified that the socket has gone bad (this is a flaw in TCP/IP); in this case AFNI may hang forever. (I've never seen this happen, so don't obsess about it.)
   - [11 Dec 2002] It used to be true that the only way for the image source to finalize the dataset(s) under construction inside AFNI was to close the data channel. To send another dataset would then require reopening the control channel, etc. However, it is now possible to send a message down the data channel that will close the current dataset(s) and leave the data channel open. After that message is sent, the next data sent should be a new set of image metadata, followed by the images for the new datasets.

     The "terminate dataset" message must be sent as a full-size image of the size that AFNI is expecting. For example, if you are sending 64x64 2D slices of shorts, AFNI reads image data in chunks of 8192 (64x64x2) bytes. The first 30 bytes of this data are used as the termination message; the rest of this data will be ignored. The message string is (without the quotes):

     > "Et Earello Endorenna utulien!!"

     This string is defined by the macro `COMMAND_MARKER` in plug_realtime.c and rtfeedme.c.
     - It is my opinion that this sequence of bytes is unlikely to occur in actual image data. If this supposition proves incorrect, please let me know by writing out the details in the margin of a US$100 bill (or several, if you need the space) and mailing it (or them) to me.

## Communicating with AFNI

IOCHANs
An external program talks to the realtime plugin using an abstract communication device called an "IOCHAN". An IOCHAN can either be a TCP/IP socket or a shared memory segment; the former would be used for communicating between computers and the latter for communicating within a single system. These routines are implemented in the files `thd_iochan.[ch]`, which are compiled into `libmri.a`.

An IOCHAN is opened with the function `iochan_init`, which takes two arguments. The first argument is a string that specifies what kind of channel is desired (TCP/IP or shared memory), and also specifies other information about the channel. The second argument is the string `"w"` for an IOCHAN that is intended to be mostly written by the caller, or is the string `"r"` for one that is intended to be mostly read by the caller. An image source program should always use `"w"`, since it is sending data to AFNI.

The format of an IOCHAN specification for a TCP/IP socket is: `"tcp:hostname:portnumber"`, where `hostname` is the computer name (or IP address in dot format) with which you wish to communicate, and `portnumber` is the TCP/IP "port number" that should be opened. For example, the realtime plugin control port number is 7954, so that to open a socket IOCHAN to the realtime plugin running on the current host, the call might be

      IOCHAN * ioc ;
      ioc = iochan_init( "tcp:localhost:7954" , "w" ) ;
      if( ioc == NULL ) fprintf(stderr,"** Failure to open control channel\n");

In this example, the IOCHAN struct pointed to by `ioc` will have a socket that is created using the Unix system call `connect`, which will reach out to the specified host to make the connection. If `"r"` were used for the second argument, the program would use the Unix system call `accept` to wait for another program to try to connect.

The format of an IOCHAN specification for a shared memory segment is: `"shm:name:size"`, where `name` is a symbolic name to be attached to the memory segment (used to distinguish it from other shared memory segments) and `size` is the size of the memory segment in bytes. This size determines the amount of data that can be transferred without blocking, and should be at least twice the size of a single image that will be transferred at one time. For example:

      IOCHAN * ioc ;
      ioc = iochan_init( "shm:Elvis:2M" , "w" ) ;
      if( ioc == NULL ) fprintf(stderr,"** Failure to open control channel\n");

In this example, `size = 2M` means a 2 megabyte buffer is used. If the "`M`" were left off, it would mean a 2 byte buffer, which would be rather useless. (You can also use the suffix "`K`" to indicate the buffer size in Kilobytes.)

> `shm` Note #1: All operating systems that I know of put a limit on the size of a shared memory segment. On some systems, this limit is fairly small. You may have to increase this limit in order to use `shm:` IOCHANs as large as the one in the example above. In all cases, changing this limit can only be done by the superuser, and depends on the Unix platform you are using.
> - On Linux, the "shmmax" kernel parameter sets the size of the largest shared memory segment. You can examine this value by the command

>         cat /proc/sys/kernel/shmmax

> - On Solaris, the command

>         /usr/bin/sysdef | grep -i SHM

>   will show the shared memory parameters. They can be altered by editing the file `/etc/system` and rebooting, but I don't know the details.

> `shm` Note #2: Another operating system dependent issue is whether the function call that deletes a shared memory segment destroys it immediately, or only marks it for destruction, with the actual destruction only occurring when all other processes detach from the segment. This makes a difference in AFNI, since the normal way for a program to close a `shm:` IOCHAN is to delete the shared memory segment. However, if this causes the immediate destruction of the segment, then the other process attached to the IOCHAN will print out some error messages, complaining that the shared memory buffer has gone bad.

> To avoid such messages, set the environment variable `IOCHAN_DELAY_RMID` to the string `YES`. Then the `shm:` IOCHAN memory buffer will only be deleted when the last process detaches from it.

> - You are probably wondering why the default action is to delete the shared memory segment immediately. The reason is that shared memory segments are perfectly capable of living on with no processes attached to them. Thus, if the image source and AFNI both crash, you'd be left with a chunk of your memory being locked up. Therefore, my original policy was to delete the shared memory segment as soon as it wasn't needed. However, this can lead to annoying error messages. Thus, the introduction of `IOCHAN_DELAY_RMID`. (BTW, `RMID` is the `shmctl()` function code for removing a shared memory segment.)

> For AFNI, you can set `IOCHAN_DELAY_RMID` in your `.afnirc` file (cf. README.environment). However, this won't affect the image source program, so you should probably set it explicitly in your `.cshrc` file (or equivalent), if needed.

> On most Unix systems, the `ipcs -m` command will show you the shared memory segments that currently exist. If something is left dangling (with 0 processes attached) from an AFNI run, you might be able to delete it with the `ipcrm` command. But be careful - you don't want to delete a shared memory segment from some other program! (For example, KDE uses shared memory to communicate.)

> If you are writing your own image source program, you can look at `rtfeedme.c` to see how to ensure that IOCHANs are closed when the program exits, even if it exits because of a crash condition (e.g., segfault). This goal is accomplished by creating a signal handler to catch fatal errors; the signal handler function then closes down any open IOCHANs before it actually exits. This technique is a way to prevent dangling shared memory segments. (Chicken soup might help, too.)

A TCP/IP IOCHAN can be used bi-directionally, once both processes have attached to it. This is not true of the shared memory IOCHAN shown above: only the writing process can write to it, and only the reading process can read from it. To avoid this difficulty, a second form of shared memory IOCHAN can be created with a specification of the form `"shm:name:size1+size2"`. Here, `size1` is the size of the buffer that will be used by the `"w"` process to write into and by the `"r"` process to read from; `size2` is the size of the buffer that will be used by the `"r"` process to write into and by the `"w"` process to read from. These sizes can be different, which might be useful if more data is expected to flow one way than another.

- The IOCHANs used in the realtime plugin need only be uni-directional. The image source program sends data to AFNI, but AFNI never sends data back.

After an IOCHAN is created, it is not necessarily ready to be used. Until the other process (AFNI in this case) attaches to the IOCHAN, no data can be sent. A number of functions are available to check if an IOCHAN is in a usable state. They are documented in the comments at the head of `thd_iochan.c`, and examples of their use can be found in `rtfeedme.c`.

The Structure of `rtfeedme.c`
This program initiates the conversation with AFNI with the function `AFNI_start_io`, which will establish the control IOCHAN, send the control information down it, close the control IOCHAN, and then open the data IOCHAN. After that is accomplished, the main program actually sends the image metadata and then finally the images themselves.

`AFNI_start_io` is designed to allow its caller to perform other functions while it is establishing the communications with AFNI. In `rtfeedme.c`, the caller (`main`) doesn't do anything, but just calls `AFNI_start_io` repeatedly until it signals that it is ready. In the MCW actual realtime image source program, `AFNI_start_io` is called once every time an echo-planar image is acquired. When the data IOCHAN is finally opened, then the stored images are sent, and after that every time a new image is acquired, it is sent immediately. `AFNI_start_io` moves through 5 modes, labeled by symbolic constants:

      #define AFNI_OPEN_CONTROL_MODE   1  /* 1st time thru: open control channel */
      #define AFNI_WAIT_CONTROL_MODE   2  /* waiting for AFNI to open control    */
      #define AFNI_OPEN_DATA_MODE      3  /* now can open data channel to AFNI   */
      #define AFNI_CATCHUP_MODE        4  /* waiting for AFNI to open data       */
      #define AFNI_CONTINUE_MODE       5  /* at last! data channel is ready!     */

The mode that the routine is in at any moment is stored in the global variable `AFNI_mode`, which should be set to `AFNI_OPEN_CONTROL_MODE` before the first call to `AFNI_start_io`. The sequence of events is outlined below (you should also read `rtfeedme.c` to see how this works):

- When the control IOCHAN is successfully opened, the mode switches to `AFNI_WAIT_CONTROL_MODE`.
- In this situation, `AFNI_start_io` simply checks if the realtime plugin has connected to the control socket. If not, `AFNI_start_io` returns without changing its mode. The caller program can then do whatever it wants (in `rtfeedme.c`, that is exactly nothing), repeatedly calling `AFNI_start_io` to have it check up on the communication status.
- When the plugin connects, `AFNI_start_io` then sends the necessary control information (more on this later), waits for it to be received, then closes the control IOCHAN, opens the data IOCHAN, and enters `AFNI_OPEN_DATA_MODE`.
- It now waits for the the realtime plugin to open the data IOCHAN itself. When this is done, the mode switches to `AFNI_CATCHUP_MODE`.
- In `rtfeedme.c`, nothing happens in this mode; in a real image source program, this is where previously acquired images could now be sent to AFNI (thus the name "catchup"). The mode now switches to `AFNI_CONTINUE_MODE`, indicating that the data IOCHAN is ready.

At this point, `AFNI_start_io` is finished, and the actual transmission of image information is the responsibility of the caller.

Realtime Control IOCHAN
When not acquiring data, the realtime plugin is listening on socket 7954, so the image source program starts talking to AFNI with the code (taken from `rtfeedme.c`):

     #define AFNI_CONTROL_PORT 7954
        char AFNI_iochan[128] , AFNI_host[128] ;
        IOCHAN * AFNI_ioc ;

        sprintf( AFNI_iochan , "tcp:%s:%d" , AFNI_host , AFNI_CONTROL_PORT ) ;
        AFNI_ioc = iochan_init( AFNI_iochan , "w" ) ;

At this point, the image source must wait until the realtime plugin connects to the newly opened socket, as described above.

When the control IOCHAN is ready, the control information should be sent. The control information is a single C NUL-terminated string, which will contain 1 or 2 lines of data. The first line of data is just the string that specifies the data IOCHAN (which can be of `shm:` or `tcp:` type).

The second line of control data, if present, specifies a command that realtime plugin should execute to obtain the image metadata. If there is no second line of data (that is, there is no `'\n'` character in the control string), then all the image metadata must come from the image source program itself. Otherwise, the realtime plugin will execute the metadata command in a child process; it will capture the standard output of this command and use that as (most of) the image metadata.

The reason for this provision is that some aspects of the images may not be known when the image source program starts. For example, at the old MCW 3 Tesla Bruker system, the image acquisition program does not know the orientation or dimensions of the data. This information must be obtained by querying the MRI console software after the acquisition actually starts. The program `3T_toafni.c` is the medium by which this query is made. The response from the MRI console is parsed and converted to AFNI image metadata, and written to `stdout`. Thus, in the MCW realtime acquisition system, the control information looks something like this:

      "shm:Elvis:1M\n3T_toafni"

Since `rtfeedme.c` will supply all the image metadata itself through the data IOCHAN, no metadata command is used in this sample program.

Data IOCHAN
When the data IOCHAN is ready, then the image source program must send some image metadata as the first transmission. (The details of the image metadata are discussed in the next section.) If an external metadata command is used to supply this information, then only one metadata command need be supplied. In the MCW 3 Tesla realtime system, this command is generated by

      char mdata[128] ;
      sprintf( mdata , "DATUM short\nXYMATRIX %d %d\n" , nx,ny ) ;

where `nx` and `ny` define the array dimensions of the reconstructed slices. (This information is not available from the MRI console, since the reconstruction matrix need not be the same as the k-space acquisition matrix.) After the NUL-terminated metadata command string, all further data that comes down the data IOCHAN is taken to be raw image slice (or volume) data.

## Image Metadata Commands

AFNI needs some information about the acquisition in order to properly construct a dataset from the images. This information is sent to AFNI as a series of command strings. A sample set of command strings is given below: [Also see the file README.realtime for full details on the Realtime plugin's metadata (AKA prolog or header).]

     ACQUISITION_TYPE 2D+zt
       TR 5.0
       XYFOV 240.0 240.0 112.0
       ZNUM 16
       XYZAXES S-I A-P L-R
       DATUM short
       XYMATRIX 64 64

The commands can be given in any order. Each command takes up a single line of input (i.e., commands are separated by the '\n' character in the input buffer, and the whole set of commands is terminated by the usual '\0'). The entire set of commands must be less than 32 Kbytes long (the usual length is about 200 characters). Each command line has one or more arguments. The full list of possible command strings and their arguments is given below.

- `ACQUISITION_TYPE arg`
  This command tells AFNI how the image data will be formatted:

          arg = 2D+z   -> a single 3D volume, one slice at a time
                2D+zt  -> multiple 3D volumes, one slice at a time [the default]
                3D     -> a single 3D volume, all at once
                3D+t   -> multiple 3D volumes, one full volume at a time

  -- This command is not required, since there is a default.
- `NAME arg`
  This command tells AFNI what name to use for the new dataset.
  -- It is not required, since AFNI will generate a name if none is given (but you may not like that name).
- `TR arg`
  This command tells AFNI what the imaging TR is, in seconds. The default value, if this command is not given, is 1.0.
  -- It is recommended that this command be used for multi-brick datasets, so that the header information is correct. But this command is not required.
- `ZDELTA dz`
  This command tells AFNI the slice thickness, in mm.
  -- This command, or `XYFOV` with 'zz'>0, MUST be used, so that the correct size of the dataset along the z-axis size known.
- `XYFOV xx yy [zz]`
  This command tells AFNI the size of the images, in mm. The first value ('xx') is the x-axis dimension, and the second value ('yy') is the y-axis dimension. If the third value ('zz') is present, then it is the z-axis dimension (slab thickness of all slices).
  -- This command MUST be used to at least to give the sizes of the dataset along the x- and y-axes. If 'zz' is not given, then the `ZDELTA` command is also required.
  -- If 'yy'==0, then it is taken to be the same as 'xx' (square images).
- `ZGAP gg`
  This command tells AFNI to add 'gg' mm to the slice thickness computed from the 'zz' parameter of `XYFOV`. If 'zz' was given in `XYFOV`, then the slice thickness is computed 'zz/znum+gg', where 'znum' is from `XYMATRIX` or `ZNUM`.
  - If the slice thickness is given explicitly via `ZDELTA`, then the value of 'gg' has no effect.
  - This option added 18 Dec 2002, per the request of Larry Frank of UCSD.
  -- This command is optional; the default 'gg' is zero.
- `ZFIRST zz[d]`
  Specifies the location of the first slice, along the z-axis, in mm. The value 'zz' gives the offset. The optional code 'd' gives the direction that distance 'zz' applies; if present, the 'd' character must immediately follow the 'zz' value, as in '50I'. The values allowed for the single character 'd' are

          I = inferior
          S = superior
          A = anterior
          P = posterior
          R = right
          L = left

  -- This command is optional - if not given, then the volume will be centered about z=0 (which is also the default for the x- and y-axes). If the direction code 'd' is given, then it must agree with the sense of the z-axis given in the `XYZAXES` command (e.g., if z-axis is I-S, the 'd' must be 'I' or 'S'). When more than one dataset is being acquired in a scanning session, then getting `ZFIRST` correct is important so that the AFNI datasets will be properly positioned relative to each other (e.g., so you can overlay SPGR and EPI data correctly).
- `XYZFIRST xx[d] yy[d] zz[d]`
  This new option [11 Dec 2002] lets you set the offsets of the dataset volume on all 3 axes. It is very similar to `ZFIRST` above, but you give values for all axes. For example:

       XYZAXES  S-I A-P L-R
         XYZFIRST 30 20A 50R

  sets
  - the x-origin to 30S (since no direction code was given for x),
  - the y-origin to 20A, and
  - the z-origin to 50R.
  - Since the z-axis is L-R and starts in the R hemisphere, these sagittal slices are all in the R hemisphere.
  - If the 'R' code had been left off the '50R', then the z-origin would have been set to 50L. Note that the origin is the CENTER of the first voxel.
  -- This command is optional. If it is given along with `ZFIRST` (why?), then whichever one comes last wins (for the z-axis).
- `XYZOFF xoff yoff zoff`
  This option is a different way of specifying the offsets of the dataset volume on all 3 axes. The default (if neither `XYZFIRST` nor `XYZOFF` is given) is to center the volume about the (x,y,z)=(0,0,0) point.
  - Centering example: If the x-axis is 240 mm and 64 pixels across, the default value of the center of the first voxel is x=0.5*(64-1)*(240/64)=118.125. The direction of this offset is the same as the first initial of 'xcode' from `XYZAXES` (e.g., if 'xcode' is 'I-S', this offset is in the 'I' direction).
  - In the case of `XYZFIRST`, the effect is to specify the center (x,y,z) of the first voxel explicitly.
  - In the case of `XYZOFF`, the effect is to shift the center of the first voxel from the default location by the amounts (xoff,yoff,zoff); in the example above, 'xoff' would be added to 118.125 to determine the x-center of the first voxel.
  - This option added 18 Dec 2002, per the request of Larry Frank of UCSD.
  -- This command is optional.
- `XYMATRIX nx ny [nz]`
  Specifies the size of the images to come, in pixels:

          nx = number of pixels along x-axis
          ny = number of pixels along y-axis
          nz = number of pixels along z-axis (optional here)

  -- This command is required. If 'nz' is not given here, then it must be given using the `ZNUM` command.
- `ZNUM nz`
  Specifies the number of pixels along the z-axis (slice direction).
  -- This value must be given, either with `XYMATRIX` or `ZNUM`.
- `DATUM typ`
  Specifies the type of data in the images:

          typ = short   -> 16 bit signed integers [the default]
                float   -> 32 bit IEEE floats
                byte    -> 8 bit unsigned integers
                complex -> 64 bit IEEE complex values (real/imag pairs)

  -- This command is not required, as long as the data are really shorts. The amount of data read for each image will be determined by this command, the `XYMATRIX` dimensions, and the `ACQUISITION_TYPE` (whether 2D or 3D data is being sent).
- `ZORDER arg`
  Specifies the order in which the slices will be read.

          arg = alt -> alternating order (e.g., slices are presented
                         to AFNI in order 1 3 5 7 9 2 4 6 8, when nz=9).
              = seq -> sequential order (e.g., slices are presented
                         to AFNI in order 1 2 3 4 5 6 7 8 9, when nz=9).

  -- This command is not required, since 'alt' is the default. It will be ignored if a 3D `ACQUISITION_TYPE` is used.
- `XYZAXES xcode ycode zcode`
  Specifies the orientation of the 3D volume data being sent to AFNI. Each of the 3 codes specifies one axis orientation, along which the corresponding pixel coordinate increases. The possible codes are:

          I-S (or IS) -> inferior-to-superior
          S-I (or SI) -> superior-to-inferior
          A-P (or AP) -> anterior-to-posterior
          P-A (or PA) -> posterior-to-anterior
          R-L (or RL) -> right-to-left
          L-R (or LR) -> left-to-right

  For example, "`XYZAXES S-I A-P L-R`" specifies a sagittal set of slices, with the slice acquisition order being left-to-right. (In this example, if `ZFIRST` is used, the 'd' code in that command must be either 'L' or 'R'.) The 3 different axes codes must point in different spatial directions (e.g., you can't say "`XYZAXES S-I A-P I-S`").
  -- This command is required, so that AFNI knows the orientation of the slices in space.
- `NUM_CHAN nc`
  Specifies the number of independent image "channels" that will be sent to AFNI. Each channel goes into a separate dataset. Channel images are interleaved; for example, if nc=3, then

          image #1 -> datataset #1
          image #2 -> datataset #2
          image #3 -> datataset #3
          image #4 -> datataset #1
          image #5 -> datataset #2
      et cetera

  - For 2D acquisitions, each slice is one "image" in the list above.
  - For 3D acquisitions, each volume is one "image".
  All channels must have the same datum type, the same xyz dimensions, and so on.
  -- This command is optional, since the default value of nc is 1.
- `DRIVE_AFNI command`
  You can also pass commands to control AFNI (e.g., open windows) in the image prolog. See README.driver for the list of command strings. More than one `DRIVE_AFNI` command can be used in the realtime prolog. Each command is executed in sequence. For example, if you wish to put new datasets into a new directory called "aaa", you could pass the commands

       DRIVE_AFNI SYSTEM mkdir aaa
         DRIVE_AFNI CHDIR aaa

  -- This command is optional.
- `NOTE text to attach to dataset`
  This command lets you attach text notes to the dataset(s) being created by the realtime plugin. All the text after "`NOTE` ", up to (not including) the next '\n', will be attached as a text note. More than one `NOTE` can be given. If you want to send a multiline note, then you have to convert the '\n' characters in the note text to '\a' or '\f' characters (ASCII 7 and 12 (decimal), respectively). Any '\a' or '\f' characters in the text will be converted to '\n' characters before the note is processed.
  -- This command is optional.

## Recording Results of rtfeedme+AFNI - April 2002

AFNI now has the ability to record the sequence of images as they are computed and displayed by the realtime plugin. (This option is distinct from saving the acquired images themselves; I'm referring to saving the images displayed in an AFNI viewer window.) The following sequence of operations would be needed:

1. You need a 3D+time AFNI dataset to simulate sending realtime data to the program.
2. Open 2 terminal windows, and cd to that directory in both of them.
3. Start AFNI with realtime I/O enabled in one of the terminals with the command "`afni -rt`".
4. Now you have to set for realtime analysis and display. To start with, open the Axial Image and Graph windows. In the Graph window, use the FIM menu (lower right corner) to "Pick Ideal", and select some 1D file as the ideal. This should then graph on top of the central sub-graph.
   - Next, in the main AFNI control window, click on "Define Datamode", then on the "Plugins" menu (lower right corner), and then on "RT Options". This opens the window that controls the realtime acquisition options. You want to set "Function" to "FIM", then press "Run+Close" to have that information saved in AFNI.
   - The function type must be set to "FIM" and the 1D ideal chosen before the images start to arrive from rtfeedme. Otherwise the correlational function analysis will not be performed.
   - Next, you want to turn on image recording in the Image window. To do this, expand the size of the Image window until you can clearly see all the buttons at the bottom. To the right of the "Done" button is "Rec". From that menu, choose "Stay On". This means that each new image that is displayed will be recorded into a special image viewer. These can then be saved later.
5. You are now ready to send the data into AFNI for realtime analysis. The command to send the dataset to AFNI via the realtime socket is

       rtfeedme -dt 300 dataset+orig

   This will feed the dataset, 300 ms per slice, to AFNI. Since you selected FIM on the RT Options plugin, you will get a sequence of colored overlays displayed in the Image window. Since Record is turned on, you will also get a new image window popping up that will contain the recorded images. Wait until the data is all sent to AFNI.
6. You can now save the recorded images to disk. To choose the format, right click on the "Save:bkg" button in the Record window (not the original Image window). You should see at least "Save.ppm". Choose that and press "Set" - then the button should now say "Save.ppm". Press this button with the left mouse click now. You get 3 dialog boxes in order, that ask for "Filename prefix", "Slice from", and "Slice to". This will let you save the images to external files named fred.0000.ppm, et cetera.
   - If program mpeg_encode is in your path, then you can also write a sequence of images to an MPEG-1 movie file. You can compile mpeg_encode from the AFNI source distribution with the command "`make mpeg_encode`".
   - Similarly, if the program gifsicle is in your path, then you can also write a sequence of images to an animated GIF file. You can compile gifsicle from the AFNI source distribution with the command "`make gifsicle`".
   - If the netpbm package of programs is compiled on your system and in your path, then AFNI can also use these to convert individual images in the viewer to TIFF, GIF, etc., files. However, netpbm is not included with AFNI.

A much simpler way would be to use a video camera or some software tool to record the screen as you run the acquisition.