Index: /trunk/psModules/src/camera/pmFPAfile.c
===================================================================
--- /trunk/psModules/src/camera/pmFPAfile.c	(revision 9949)
+++ /trunk/psModules/src/camera/pmFPAfile.c	(revision 9950)
@@ -119,4 +119,52 @@
 }
 
+// select the cell from the named pmFPAfile; if the named file does not exist,
+pmCell *pmFPAfileThisCell (psMetadata *files, const pmFPAview *view, const char *name)
+{
+    PS_ASSERT_PTR_NON_NULL(files, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+    PS_ASSERT_PTR_NON_NULL(name, false);
+    PS_ASSERT_INT_POSITIVE(strlen(name), false);
+
+    bool status;
+
+    pmFPAfile *file = psMetadataLookupPtr (&status, files, name);
+    if (file == NULL) {
+        return NULL;
+    }
+
+    // internal files have the readout as a separate element:
+    if (file->mode == PM_FPA_MODE_INTERNAL) {
+        return NULL;
+    }
+
+    pmCell *cell = pmFPAviewThisCell(view, file->fpa);
+    return cell;
+}
+
+// select the readout from the named pmFPAfile; if the named file does not exist,
+pmChip *pmFPAfileThisChip (psMetadata *files, const pmFPAview *view, const char *name)
+{
+    PS_ASSERT_PTR_NON_NULL(files, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+    PS_ASSERT_PTR_NON_NULL(name, false);
+    PS_ASSERT_INT_POSITIVE(strlen(name), false);
+
+    bool status;
+
+    pmFPAfile *file = psMetadataLookupPtr (&status, files, name);
+    if (file == NULL) {
+        return NULL;
+    }
+
+    // internal files have the readout as a separate element:
+    if (file->mode == PM_FPA_MODE_INTERNAL) {
+        return NULL;
+    }
+
+    pmChip *chip = pmFPAviewThisChip (view, file->fpa);
+    return chip;
+}
+
 // select the rule from the camera configuration, perform substitutions as needed
 char *pmFPAfileNameFromRule (char *rule, pmFPAfile *file, const pmFPAview *view)
@@ -296,2 +344,39 @@
     return false;
 }
+
+
+pmFPAfileType pmFPAfileTypeFromString(const char *type)
+{
+    PS_ASSERT_STRING_NON_EMPTY(type, PM_FPA_FILE_NONE);
+
+    if (!strcasecmp (type, "SX"))     {
+        return PM_FPA_FILE_SX;
+    }
+    if (!strcasecmp (type, "OBJ"))     {
+        return PM_FPA_FILE_OBJ;
+    }
+    if (!strcasecmp (type, "CMP"))     {
+        return PM_FPA_FILE_CMP;
+    }
+    if (!strcasecmp (type, "CMF"))     {
+        return PM_FPA_FILE_CMF;
+    }
+    if (!strcasecmp (type, "RAW"))     {
+        return PM_FPA_FILE_RAW;
+    }
+    if (!strcasecmp (type, "IMAGE"))     {
+        return PM_FPA_FILE_IMAGE;
+    }
+    if (!strcasecmp (type, "PSF"))     {
+        return PM_FPA_FILE_PSF;
+    }
+    if (!strcasecmp (type, "JPEG"))     {
+        return PM_FPA_FILE_JPEG;
+    }
+    if (!strcasecmp (type, "FRINGE")) {
+        return PM_FPA_FILE_FRINGE;
+    }
+
+    return PM_FPA_FILE_NONE;
+}
+
Index: /trunk/psModules/src/camera/pmFPAfile.h
===================================================================
--- /trunk/psModules/src/camera/pmFPAfile.h	(revision 9949)
+++ /trunk/psModules/src/camera/pmFPAfile.h	(revision 9950)
@@ -7,6 +7,6 @@
 *  @author EAM, IfA
 *
-*  @version $Revision: 1.6 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2006-10-17 00:41:05 $
+*  @version $Revision: 1.7 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-11-13 22:15:55 $
 *
 *  Copyright 2004-2005 Institute for Astronomy, University of Hawaii
@@ -37,4 +37,5 @@
     PM_FPA_FILE_JPEG,
     PM_FPA_FILE_MANAPLOT,
+    PM_FPA_FILE_FRINGE,
 } pmFPAfileType;
 
@@ -101,4 +102,10 @@
 pmReadout *pmFPAfileThisReadout (psMetadata *files, const pmFPAview *view, const char *name);
 
+// select the cell from the named pmFPAfile; if the named file does not exist,
+pmCell *pmFPAfileThisCell (psMetadata *files, const pmFPAview *view, const char *name);
+
+// select the chip from the named pmFPAfile; if the named file does not exist,
+pmChip *pmFPAfileThisChip (psMetadata *files, const pmFPAview *view, const char *name);
+
 // add the specified filename info (value) to the files of the given mode using the given reference name
 bool pmFPAfileAddFileNames (psMetadata *files, char *name, char *value, int mode);
@@ -111,3 +118,6 @@
 bool pmFPAfileCopyStructureView (pmFPA *out, pmFPA *in, int xBin, int yBin, const pmFPAview *view);
 
+// Return the file type enum from a string
+pmFPAfileType pmFPAfileTypeFromString(const char *type);
+
 # endif
Index: /trunk/psModules/src/camera/pmFPAfileDefine.c
===================================================================
--- /trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 9949)
+++ /trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 9950)
@@ -71,25 +71,6 @@
     file->extxtra  = psMemIncrRefCounter(psMetadataLookupStr (&status, data, "EXTNAME.XTRA"));
 
-    file->type = PM_FPA_FILE_NONE;
     type = psMetadataLookupStr (&status, data, "FILE.TYPE");
-    if (type != NULL) {
-        if (!strcasecmp (type, "SX"))     {
-            file->type = PM_FPA_FILE_SX;
-        } else if (!strcasecmp (type, "OBJ"))     {
-            file->type = PM_FPA_FILE_OBJ;
-        } else if (!strcasecmp (type, "CMP"))     {
-            file->type = PM_FPA_FILE_CMP;
-        } else if (!strcasecmp (type, "CMF"))     {
-            file->type = PM_FPA_FILE_CMF;
-        } else if (!strcasecmp (type, "RAW"))     {
-            file->type = PM_FPA_FILE_RAW;
-        } else if (!strcasecmp (type, "IMAGE"))     {
-            file->type = PM_FPA_FILE_IMAGE;
-        } else if (!strcasecmp (type, "PSF"))     {
-            file->type = PM_FPA_FILE_PSF;
-        } else if (!strcasecmp (type, "JPEG"))     {
-            file->type = PM_FPA_FILE_JPEG;
-        }
-    }
+    file->type = pmFPAfileTypeFromString(type);
     if (file->type == PM_FPA_FILE_NONE) {
         psError(PS_ERR_IO, true, "FILE.TYPE is not defined for %s\n", name);
@@ -167,25 +148,6 @@
     file->extxtra  = psMemIncrRefCounter(psMetadataLookupStr (&status, data, "EXTNAME.XTRA"));
 
-    file->type = PM_FPA_FILE_NONE;
     type = psMetadataLookupStr (&status, data, "FILE.TYPE");
-    if (type != NULL) {
-        if (!strcasecmp (type, "SX"))     {
-            file->type = PM_FPA_FILE_SX;
-        } else if (!strcasecmp (type, "OBJ"))     {
-            file->type = PM_FPA_FILE_OBJ;
-        } else if (!strcasecmp (type, "CMP"))     {
-            file->type = PM_FPA_FILE_CMP;
-        } else if (!strcasecmp (type, "CMF"))     {
-            file->type = PM_FPA_FILE_CMF;
-        } else if (!strcasecmp (type, "RAW"))     {
-            file->type = PM_FPA_FILE_RAW;
-        } else if (!strcasecmp (type, "IMAGE"))     {
-            file->type = PM_FPA_FILE_IMAGE;
-        } else if (!strcasecmp (type, "PSF"))     {
-            file->type = PM_FPA_FILE_PSF;
-        } else if (!strcasecmp (type, "JPEG"))     {
-            file->type = PM_FPA_FILE_JPEG;
-        }
-    }
+    file->type = pmFPAfileTypeFromString(type);
     if (file->type == PM_FPA_FILE_NONE) {
         psError(PS_ERR_IO, true, "FILE.TYPE is not defined for %s\n", name);
Index: /trunk/psModules/src/camera/pmFPAfileFitsIO.c
===================================================================
--- /trunk/psModules/src/camera/pmFPAfileFitsIO.c	(revision 9949)
+++ /trunk/psModules/src/camera/pmFPAfileFitsIO.c	(revision 9950)
@@ -16,4 +16,48 @@
 #include "pmFPAfile.h"
 #include "pmFPAfileFitsIO.h"
+
+// given an already-opened fits file, read the table corresponding to the specified view
+bool pmFPAviewReadFitsTable(const pmFPAview *view, pmFPAfile *file, const char *name)
+{
+    PS_ASSERT_PTR_NON_NULL(view, false);
+    PS_ASSERT_PTR_NON_NULL(file, false);
+
+    pmFPA *fpa = file->fpa;             // FPA of interest
+    psFits *fits = file->fits;          // FITS file
+
+    if (view->chip == -1) {
+        return pmFPAReadTable(fpa, fits, name) > 0;
+    }
+
+    if (view->cell == -1) {
+        pmChip *chip = pmFPAviewThisChip(view, fpa); // Chip of interest
+        return pmChipReadTable(chip, fits, name) > 0;
+    }
+
+    pmCell *cell = pmFPAviewThisCell(view, fpa); // Cell of interest
+    return pmCellReadTable(cell, fits, name) > 0;
+}
+
+// given an already-opened fits file, write the table corresponding to the specified view
+bool pmFPAviewWriteFitsTable(const pmFPAview *view, pmFPAfile *file, const char *name)
+{
+    PS_ASSERT_PTR_NON_NULL(view, false);
+    PS_ASSERT_PTR_NON_NULL(file, false);
+
+    pmFPA *fpa = file->fpa;             // FPA of interest
+    psFits *fits = file->fits;          // FITS file
+
+    if (view->chip == -1) {
+        return pmFPAWriteTable(fits, fpa, name) > 0;
+    }
+
+    if (view->cell == -1) {
+        pmChip *chip = pmFPAviewThisChip(view, fpa); // Chip of interest
+        return pmChipWriteTable(fits, chip, name) > 0;
+    }
+
+    pmCell *cell = pmFPAviewThisCell(view, fpa); // Cell of interest
+    return pmCellWriteTable(fits, cell, name) > 0;
+}
 
 // given an already-opened fits file, read the components corresponding
@@ -226,2 +270,61 @@
 }
 
+
+// Free the table within a cell
+static void freeTable(pmCell *cell,     // Cell of interest
+                      const char *name  // Name of table to free
+                     )
+{
+    assert(cell);
+    assert(name && strlen(name) > 0);
+
+    psString headerName = NULL;         // Name of header
+    psStringAppend(&headerName, "%s.HEADER", name);
+    if (psMetadataLookup(cell->analysis, headerName)) {
+        psMetadataRemoveKey(cell->analysis, headerName);
+    }
+    psFree(headerName);
+
+    if (psMetadataLookup(cell->analysis, name)) {
+        psMetadataRemoveKey(cell->analysis, name);
+    }
+
+    return;
+}
+
+// given a file, free the components corresponding to the specified view
+bool pmFPAviewFreeFitsTable (const pmFPAview *view, pmFPAfile *file, const char *name)
+{
+    PS_ASSERT_PTR_NON_NULL(view, false);
+    PS_ASSERT_PTR_NON_NULL(file, false);
+
+    pmFPA *fpa = file->fpa;
+
+    if (view->chip == -1) {
+        psArray *chips = fpa->chips;    // Array of chips
+        for (int i = 0; i < chips->n; i++) {
+            pmChip *chip = chips->data[i]; // Chip of interest
+            psArray *cells = chip->cells; // Array of cells
+            for (int j = 0; j < cells->n; j++) {
+                pmCell *cell = cells->data[j]; // Cell of interest
+                freeTable(cell, name);
+            }
+        }
+        return true;
+    }
+
+    if (view->cell == -1) {
+        pmChip *chip = pmFPAviewThisChip(view, fpa); // Chip of interest
+        psArray *cells = chip->cells;   // Array of cells
+        for (int i = 0; i < cells->n; i++) {
+            pmCell *cell = cells->data[i]; // Cell of interest
+            freeTable(cell, name);
+        }
+        return true;
+    }
+
+    pmCell *cell = pmFPAviewThisCell(view, fpa); // Cell of interest
+    freeTable(cell, name);
+    return true;
+}
+
Index: /trunk/psModules/src/camera/pmFPAfileFitsIO.h
===================================================================
--- /trunk/psModules/src/camera/pmFPAfileFitsIO.h	(revision 9949)
+++ /trunk/psModules/src/camera/pmFPAfileFitsIO.h	(revision 9950)
@@ -7,6 +7,6 @@
 *  @author EAM, IfA
 *
-*  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2006-06-17 01:50:43 $
+*  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-11-13 22:15:55 $
 *
 *  Copyright 2004-2005 Institute for Astronomy, University of Hawaii
@@ -25,3 +25,13 @@
 bool pmFPAviewFreeFitsImage (const pmFPAview *view, pmFPAfile *file);
 
+
+// read a table into the current view
+bool pmFPAviewReadFitsTable(const pmFPAview *view, pmFPAfile *file, const char *name);
+
+// write the table for the specified view
+bool pmFPAviewWriteFitsTable(const pmFPAview *view, pmFPAfile *file, const char *name);
+
+// free the appropriate table containers
+bool pmFPAviewFreeFitsTable(const pmFPAview *view, pmFPAfile *file, const char *name);
+
 # endif
Index: /trunk/psModules/src/camera/pmFPAfileIO.c
===================================================================
--- /trunk/psModules/src/camera/pmFPAfileIO.c	(revision 9949)
+++ /trunk/psModules/src/camera/pmFPAfileIO.c	(revision 9950)
@@ -30,4 +30,96 @@
 #include "pmDetrendDB.h"
 
+// Open a file that contains an image
+static bool openImage(pmFPAfile *file,  // File to open
+                      const pmFPAview *view, // View pointing to open level
+                      const char *mode,  // Open mode (for psFitsOpen)
+                      pmConfig *config  // Configuration
+                     )
+{
+    file->fits = psFitsOpen (file->filename, mode);
+    if (file->fits == NULL) {
+        psError(PS_ERR_IO, false, "error opening file %s\n", file->filename);
+        return false;
+    }
+    file->state = PM_FPA_STATE_OPEN;
+
+    // In some cases, I need to call pmFPAAddSourceFromHeader after I've opened the file,
+    // specifically if I have not called this function on startup.  This happens for the
+    // images supplied by the detrend database, which are only identified here (above).
+    // this is never true for the output images, which are constructed later
+
+    if (file->mode == PM_FPA_MODE_READ) {
+        bool addSource = false;
+        switch (file->fileLevel) {
+        case PM_FPA_LEVEL_FPA:
+            addSource = !file->fpa->hdu;
+            break;
+        case PM_FPA_LEVEL_CHIP: {
+                pmChip *chip = pmFPAviewThisChip(view, file->fpa);
+                if (!chip) {
+                    psError (PS_ERR_IO, true, "inconsistent file/fpa: fileLevel is CHIP, view is FPA");
+                    return false;
+                }
+                addSource = !chip->hdu;
+                break;
+            }
+        case PM_FPA_LEVEL_CELL: {
+                pmCell *cell = pmFPAviewThisCell(view, file->fpa);
+                if (!cell) {
+                    psError (PS_ERR_IO, true, "inconsistent file/fpa: fileLevel is CELL, view is FPA");
+                    return false;
+                }
+                addSource = !cell->hdu;
+                break;
+            }
+        default:
+            psAbort ("pmFPAfileIO", "fileLevel not correctly set");
+            break;
+        }
+
+        if (addSource) {
+            psMetadata *phu = psFitsReadHeader (NULL, file->fits);
+            if (!file->format) {
+                file->format = pmConfigCameraFormatFromHeader (config, phu);
+                if (!file->format) {
+                    psError(PS_ERR_IO, false, "Failed to read CCD format from %s\n", file->filename);
+                    psFree(phu);
+                    return NULL;
+                }
+            } else {
+                pmConfigValidateCameraFormat (file->format, phu);
+            }
+            pmFPAview *thisView = pmFPAAddSourceFromHeader (file->fpa, phu, file->format);
+            psFree (thisView);
+            psFree (phu);
+            // XXX we can check the output view to be sure it corresponds to our current view
+        }
+    }
+    if (file->mode == PM_FPA_MODE_WRITE) {
+        switch (file->fileLevel) {
+        case PM_FPA_LEVEL_FPA:
+            pmFPAWrite (file->fpa, file->fits, NULL, true, false);
+            break;
+        case PM_FPA_LEVEL_CHIP: {
+                pmChip *chip = pmFPAviewThisChip(view, file->fpa);
+                pmChipWrite (chip, file->fits, NULL, true, false);
+                break;
+            }
+        case PM_FPA_LEVEL_CELL: {
+                pmCell *cell = pmFPAviewThisCell(view, file->fpa);
+                pmCellWrite(cell, file->fits, NULL, true);
+                break;
+            }
+        default:
+            psAbort ("pmFPAfileIO", "fileLevel not correctly set");
+            break;
+        }
+    }
+
+    return true;
+
+}
+
+
 // open file (if not already opened)
 bool pmFPAfileOpen (pmFPAfile *file, const pmFPAview *view, pmConfig *config)
@@ -133,86 +225,11 @@
         // open the FITS types:
     case PM_FPA_FILE_IMAGE:
+    case PM_FPA_FILE_FRINGE:
         psTrace ("pmFPAfile", 5, "opening %s (type: %d)\n", file->filename, file->type);
-        file->fits = psFitsOpen (file->filename, mode);
-        if (file->fits == NULL) {
-            psError(PS_ERR_IO, false, "error opening file %s\n", file->filename);
-            return false;
-        }
-        file->state = PM_FPA_STATE_OPEN;
-
-        // In some cases, I need to call pmFPAAddSourceFromHeader after I've opened the file,
-        // specifically if I have not called this function on startup.  This happens for the
-        // images supplied by the detrend database, which are only identified here (above).
-        // this is never true for the output images, which are constructed later
-
-        if (file->mode == PM_FPA_MODE_READ) {
-            pmChip *chip;
-            pmCell *cell;
-            bool addSource = false;
-            switch (file->fileLevel) {
-            case PM_FPA_LEVEL_FPA:
-                addSource = !file->fpa->hdu;
-                break;
-            case PM_FPA_LEVEL_CHIP:
-                chip = pmFPAviewThisChip(view, file->fpa);
-                if (!chip) {
-                    psError (PS_ERR_IO, true, "inconsistent file/fpa: fileLevel is CHIP, view is FPA");
-                    return false;
-                }
-                addSource = !chip->hdu;
-                break;
-            case PM_FPA_LEVEL_CELL:
-                cell = pmFPAviewThisCell(view, file->fpa);
-                if (!cell) {
-                    psError (PS_ERR_IO, true, "inconsistent file/fpa: fileLevel is CELL, view is FPA");
-                    return false;
-                }
-                addSource = !cell->hdu;
-                break;
-            default:
-                psAbort ("pmFPAfileIO", "fileLevel not correctly set");
-                break;
-            }
-
-            if (addSource) {
-                psMetadata *phu = psFitsReadHeader (NULL, file->fits);
-                if (!file->format) {
-                    file->format = pmConfigCameraFormatFromHeader (config, phu);
-                    if (!file->format) {
-                        psError(PS_ERR_IO, false, "Failed to read CCD format from %s\n", file->filename);
-                        psFree(phu);
-                        return NULL;
-                    }
-                } else {
-                    pmConfigValidateCameraFormat (file->format, phu);
-                }
-                pmFPAview *thisView = pmFPAAddSourceFromHeader (file->fpa, phu, file->format);
-                psFree (thisView);
-                psFree (phu);
-                // XXX we can check the output view to be sure it corresponds to our current view
-            }
-        }
-        if (file->mode == PM_FPA_MODE_WRITE) {
-            switch (file->fileLevel) {
-            case PM_FPA_LEVEL_FPA:
-                pmFPAWrite (file->fpa, file->fits, NULL, true, false);
-                break;
-            case PM_FPA_LEVEL_CHIP: {
-                    pmChip *chip = pmFPAviewThisChip(view, file->fpa);
-                    pmChipWrite (chip, file->fits, NULL, true, false);
-                    break;
-                }
-            case PM_FPA_LEVEL_CELL: {
-                    pmCell *cell = pmFPAviewThisCell(view, file->fpa);
-                    pmCellWrite(cell, file->fits, NULL, true);
-                    break;
-                }
-            default:
-                psAbort ("pmFPAfileIO", "fileLevel not correctly set");
-                break;
-            }
-        }
-        break;
-
+        if (!openImage(file, view, mode, config)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to open image %s (type %d)\n", file->filename, file->type);
+            return false;
+        }
+        break;
         // open the FITS object files
     case PM_FPA_FILE_CMF:
@@ -294,10 +311,22 @@
     switch (file->type) {
     case PM_FPA_FILE_IMAGE:
-        if (pmFPAviewReadFitsImage (view, file)) {
-            psTrace ("pmFPAfile", 5, "reading %s (type: %d)\n", file->filename, file->type);
-        } else {
+        if (!pmFPAviewReadFitsImage (view, file)) {
             psError(PS_ERR_UNKNOWN, false, "skipping %s (type: %d)\n", file->filename, file->type);
             return false;
         }
+        psTrace ("pmFPAfile", 5, "reading %s (type: %d)\n", file->filename, file->type);
+        break;
+    case PM_FPA_FILE_FRINGE:
+        if (!pmFPAviewReadFitsImage (view, file)) {
+            psError(PS_ERR_UNKNOWN, false, "skipping %s (type: %d)\n", file->filename, file->type);
+            return false;
+        }
+        psTrace ("pmFPAfile", 5, "reading %s (type: %d)\n", file->filename, file->type);
+
+        if (!pmFPAviewReadFitsTable(view, file, "FRINGE")) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to read fringe data from %s.\n", file->filename);
+            return false;
+        }
+
         break;
 
@@ -365,4 +394,10 @@
         }
         break;
+    case PM_FPA_FILE_FRINGE:
+        if (!pmFPAviewFreeFitsTable(view, file, "FRINGE")) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to free fringe data.\n");
+            return false;
+        }
+        break;
 
     case PM_FPA_FILE_SX:
@@ -436,4 +471,10 @@
         pmFPAviewWriteFitsImage (view, file);
         psTrace ("pmFPAfile", 5, "wrote image %s (fpa: %p)\n", file->filename, file->fpa);
+        break;
+    case PM_FPA_FILE_FRINGE:
+        pmFPAviewWriteFitsImage (view, file);
+        psTrace ("pmFPAfile", 5, "wrote table %s (fpa: %p)\n", file->filename, file->fpa);
+        pmFPAviewWriteFitsTable(view, file, "FRINGE");
+        psTrace ("pmFPAfile", 5, "wrote fringe table %s (fpa: %p)\n", file->filename, file->fpa);
         break;
 
@@ -513,5 +554,5 @@
     switch (file->type) {
     case PM_FPA_FILE_IMAGE:
-
+    case PM_FPA_FILE_FRINGE:
         // create FPA structure component based on view
         pmFPAAddSourceFromView (file->fpa, view, file->format);
@@ -567,4 +608,5 @@
         // check the FITS types
     case PM_FPA_FILE_IMAGE:
+    case PM_FPA_FILE_FRINGE:
     case PM_FPA_FILE_CMF:
         psFitsClose (file->fits);
