Index: trunk/psModules/src/camera/pmFPAfileIO.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfileIO.c	(revision 9654)
+++ 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);
