Index: trunk/psModules/src/camera/pmFPARead.c
===================================================================
--- trunk/psModules/src/camera/pmFPARead.c	(revision 9998)
+++ trunk/psModules/src/camera/pmFPARead.c	(revision 10081)
@@ -16,4 +16,15 @@
 
 #include "pmFPARead.h"
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Definitions
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Specify what to read
+typedef enum {
+    FPA_READ_TYPE_IMAGE,                // Read image
+    FPA_READ_TYPE_MASK,                 // Read mask
+    FPA_READ_TYPE_WEIGHT                // Read weight map
+} fpaReadType;
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -155,6 +166,177 @@
 }
 
+
+// Read into an cell; this is the engine for pmCellRead, pmCellReadMask, pmCellReadWeight
+// Does most of the work for the reading --- reads the HDU, and portions the HDU into readouts.
+static bool cellRead(pmCell *cell,      // Cell into which to read
+                     psFits *fits,      // FITS file from which to read
+                     psDB *db,          // Database handle, for concepts ingest
+                     fpaReadType type   // Type to read
+                    )
+{
+    assert(cell);
+    assert(fits);
+
+    pmHDU *hdu = pmHDUFromCell(cell);   // The HDU
+    if (!hdu) {
+        return true;                    // We read everything we could
+    }
+
+    bool (*hduReadFunc)(pmHDU*, psFits*); // Function to use to read the HDU
+    psArray **imageArray;               // Array of images in the HDU
+    psElemType imageType;               // Expected type for image
+    switch (type) {
+    case FPA_READ_TYPE_IMAGE:
+        hduReadFunc = pmHDURead;
+        imageArray = &hdu->images;
+        imageType = PS_TYPE_F32;
+        break;
+    case FPA_READ_TYPE_MASK:
+        hduReadFunc = pmHDUReadMask;
+        imageArray = &hdu->masks;
+        imageType = PS_TYPE_MASK;
+        break;
+    case FPA_READ_TYPE_WEIGHT:
+        hduReadFunc = pmHDUReadWeight;
+        imageArray = &hdu->weights;
+        imageType = PS_TYPE_F32;
+        break;
+    default:
+        psAbort(__func__, "Unknown read type: %x\n", type);
+    }
+
+    if (!(*imageArray) && !hduReadFunc(hdu, fits)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to read HDU for cell.\n");
+        return false;
+    }
+
+    if (!pmConceptsReadCell(cell, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
+        //psError(PS_ERR_UNKNOWN, false, "Failed to read concepts for cell");
+        //return false;
+        psWarning("Difficulty reading concepts for cell; attempting to proceed.");
+    }
+
+    // Having read the cell, we now have to cut it up
+    psRegion *trimsec = psMetadataLookupPtr(NULL, cell->concepts, "CELL.TRIMSEC");
+    psList *biassecs = psMetadataLookupPtr(NULL, cell->concepts, "CELL.BIASSEC");
+    if (psRegionIsNaN(*trimsec)) {
+        psError(PS_ERR_IO, false, "CELL.TRIMSEC is not set --- can't read cell.\n");
+        return false;
+    }
+
+    // Iterate over each of the image planes, converting type if necessary, and extracting the bits that
+    // matter (CELL.TRIMSEC, CELL.BIASSEC) into readouts with readoutCarve.
+    for (int i = 0; i < (*imageArray)->n; i++) {
+        psImage *source = (*imageArray)->data[i]; // Source image, from the i-th plane
+
+        // Type conversion here to support the modules, which don't have multiple type support yet
+        if (source->type.type != imageType) {
+            psImage *temp = psImageCopy(NULL, source, imageType); // Temporary image
+            psFree((*imageArray)->data[i]);
+            (*imageArray)->data[i] = temp;
+            source = temp;
+        }
+
+        pmReadout *readout;             // Readout into which to read
+        if (cell->readouts->n > i && cell->readouts->data[i]) {
+            readout = psMemIncrRefCounter(cell->readouts->data[i]);
+        } else {
+            readout = pmReadoutAlloc(cell);
+        }
+
+        psImage **target;               // Place in readout to put carved image
+        switch (type) {
+        case FPA_READ_TYPE_IMAGE:
+            target = &readout->image;
+            break;
+        case FPA_READ_TYPE_MASK:
+            target = &readout->mask;
+            break;
+        case FPA_READ_TYPE_WEIGHT:
+            target = &readout->weight;
+            break;
+        default:
+            psAbort(__func__, "Unknown read type: %x\n", type);
+        }
+
+        if (!readoutCarve(readout, target, source, trimsec, biassecs)) {
+            psError(PS_ERR_UNEXPECTED_NULL, false,
+                    "Unable to carve readout into image and bias sections for %d the plane.", i);
+            return NULL;
+        }
+        psFree(readout);                // Drop reference
+    }
+
+    pmCellSetDataStatus(cell, true);
+    return true;
+}
+
+
+// Read into an chip; this is the engine for pmChipRead, pmChipReadMask, pmChipReadWeight
+// Iterates over component cells, reading each
+static bool chipRead(pmChip *chip,      // Chip into which to read
+                     psFits *fits,      // FITS file from which to read
+                     psDB *db,          // Database handle, for concepts ingest
+                     fpaReadType type   // Type to read
+                    )
+{
+    assert(chip);
+    assert(fits);
+
+    bool success = false;               // Were we able to read at least one HDU?
+    psArray *cells = chip->cells;       // Array of cells
+    for (int i = 0; i < cells->n; i++) {
+        pmCell *cell = cells->data[i];  // The cell of interest
+        success |= cellRead(cell, fits, db, type);
+    }
+    if (success) {
+        if (!pmConceptsReadChip(chip, PM_CONCEPT_SOURCE_HEADER, true, true, NULL)) {
+            psError(PS_ERR_IO, false, "Failed to read concepts for FPA.\n");
+            return false;
+        }
+        // XXX probably could just use chip->data_exists
+        pmChipSetDataStatus(chip, true);
+    }
+
+    return success;
+}
+
+
+// Read into an FPA; this is the engine for pmFPARead, pmFPAReadMask, pmFPAReadWeight
+// Iterates over component chips, reading each
+static bool fpaRead(pmFPA *fpa,         // FPA into which to read
+                    psFits *fits,       // FITS file from which to read
+                    psDB *db,           // Database handle, for concepts ingest
+                    fpaReadType type    // Type to read
+                   )
+{
+    assert(fpa);
+    assert(fits);
+
+    bool success = false;               // Were we able to read at least one HDU?
+    psArray *chips = fpa->chips;        // Array of chips
+    for (int i = 0; i < chips->n; i++) {
+        pmChip *chip = chips->data[i];  // The cell of interest
+        success |= chipRead(chip, fits, db, type);
+    }
+    if (success) {
+        if (!pmConceptsReadFPA(fpa, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
+            psError(PS_ERR_IO, false, "Failed to read concepts for FPA.\n");
+            return false;
+        }
+    } else {
+        psError(PS_ERR_UNKNOWN, false, "Unable to read any chips in FPA");
+    }
+
+    return success;
+}
+
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
 // Public functions
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Reading images
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -325,55 +507,5 @@
     PS_ASSERT_PTR_NON_NULL(fits, false);
 
-    pmHDU *hdu = pmHDUFromCell(cell);   // The HDU
-    if (!hdu) {
-        return true;                    // We read everything we could
-    }
-    if (!hdu->images && !pmHDURead(hdu, fits)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to read HDU for cell.\n");
-        return false;
-    }
-
-    if (!pmConceptsReadCell(cell, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
-        //psError(PS_ERR_UNKNOWN, false, "Failed to read concepts for cell");
-        //return false;
-        psWarning("Difficulty reading concepts for cell; attempting to proceed.");
-    }
-
-    // Having read the cell, we now have to cut it up
-    psRegion *trimsec = psMetadataLookupPtr(NULL, cell->concepts, "CELL.TRIMSEC");
-    psList *biassecs = psMetadataLookupPtr(NULL, cell->concepts, "CELL.BIASSEC");
-    if (psRegionIsNaN(*trimsec)) {
-        psError(PS_ERR_IO, false, "CELL.TRIMSEC is not set --- can't read cell.\n");
-        return false;
-    }
-
-    // Iterate over each of the image planes
-    for (int i = 0; i < hdu->images->n; i++) {
-        psImage *image = hdu->images->data[i]; // The i-th plane
-
-        // XXX: Type conversion here to support the modules, which don't have multiple type support yet
-        if (image->type.type != PS_TYPE_F32) {
-            psImage *temp = psImageCopy(NULL, image, PS_TYPE_F32); // Temporary image
-            psFree(hdu->images->data[i]);
-            hdu->images->data[i] = temp;
-            image = temp;
-        }
-
-        pmReadout *readout;             // Readout into which to read
-        if (cell->readouts->n > i && cell->readouts->data[i]) {
-            readout = psMemIncrRefCounter(cell->readouts->data[i]);
-        } else {
-            readout = pmReadoutAlloc(cell);
-        }
-        if (!readoutCarve(readout, &readout->image, image, trimsec, biassecs)) {
-            psError(PS_ERR_UNEXPECTED_NULL, false,
-                    "Unable to carve readout into image and bias sections for %d the plane.", i);
-            return NULL;
-        }
-        psFree(readout);                // Drop reference
-    }
-
-    pmCellSetDataStatus(cell, true);
-    return true;
+    return cellRead(cell, fits, db, FPA_READ_TYPE_IMAGE);
 }
 
@@ -383,20 +515,5 @@
     PS_ASSERT_PTR_NON_NULL(fits, false);
 
-    bool success = false;               // Were we able to read at least one HDU?
-    psArray *cells = chip->cells;       // Array of cells
-    for (int i = 0; i < cells->n; i++) {
-        pmCell *cell = cells->data[i];  // The cell of interest
-        success |= pmCellRead(cell, fits, db);
-    }
-    if (success) {
-        if (!pmConceptsReadChip(chip, PM_CONCEPT_SOURCE_HEADER, true, true, NULL)) {
-            psError(PS_ERR_IO, false, "Failed to read concepts for FPA.\n");
-            return false;
-        }
-        // XXX probably could just use chip->data_exists
-        pmChipSetDataStatus(chip, true);
-    }
-
-    return success;
+    return chipRead(chip, fits, db, FPA_READ_TYPE_IMAGE);
 }
 
@@ -406,20 +523,5 @@
     PS_ASSERT_PTR_NON_NULL(fits, false);
 
-    bool success = false;               // Were we able to read at least one HDU?
-    psArray *chips = fpa->chips;        // Array of chips
-    for (int i = 0; i < chips->n; i++) {
-        pmChip *chip = chips->data[i];  // The cell of interest
-        success |= pmChipRead(chip, fits, db);
-    }
-    if (success) {
-        if (!pmConceptsReadFPA(fpa, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
-            psError(PS_ERR_IO, false, "Failed to read concepts for FPA.\n");
-            return false;
-        }
-    } else {
-        psError(PS_ERR_UNKNOWN, false, "Unable to read any chips in FPA");
-    }
-
-    return success;
+    return fpaRead(fpa, fits, db, FPA_READ_TYPE_IMAGE);
 }
 
@@ -434,48 +536,5 @@
     PS_ASSERT_PTR_NON_NULL(fits, false);
 
-    pmHDU *hdu = pmHDUFromCell(cell);   // The HDU
-    if (!hdu) {
-        return false;                    // Nothing to see here; move along
-    }
-    if (!hdu->images && !pmHDURead(hdu, fits)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to read HDU for cell.\n");
-        return false;
-    }
-
-    if (!pmConceptsReadCell(cell, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
-        psError(PS_ERR_UNKNOWN, false, "Failed to read concepts for cell");
-        return false;
-    }
-
-    // Having read the cell, we now have to cut it up
-    psRegion *trimsec = psMetadataLookupPtr(NULL, cell->concepts, "CELL.TRIMSEC");
-
-    // Iterate over each of the image planes
-    for (int i = 0; i < hdu->images->n; i++) {
-        psImage *image = hdu->images->data[i]; // The i-th plane
-
-        if (image->type.type != PS_TYPE_U8) {
-            psImage *temp = psImageCopy(NULL, image, PS_TYPE_U8); // Temporary image
-            psFree(hdu->images->data[i]);
-            hdu->images->data[i] = temp;
-            image = temp;
-        }
-
-        pmReadout *readout;             // Readout into which to read
-        if (cell->readouts->n > i && cell->readouts->data[i]) {
-            readout = psMemIncrRefCounter(cell->readouts->data[i]);
-        } else {
-            readout = pmReadoutAlloc(cell);
-        }
-        if (!readoutCarve(readout, &readout->mask, image, trimsec, NULL)) {
-            psError(PS_ERR_UNEXPECTED_NULL, false,
-                    "Unable to carve readout into image and bias sections for %d the plane.", i);
-            return NULL;
-        }
-        psFree(readout);                // Drop reference
-    }
-
-    pmCellSetDataStatus(cell, true);
-    return true;
+    return cellRead(cell, fits, db, FPA_READ_TYPE_MASK);
 }
 
@@ -485,20 +544,5 @@
     PS_ASSERT_PTR_NON_NULL(fits, false);
 
-    bool success = false;               // Were we able to read at least one HDU?
-    psArray *cells = chip->cells;       // Array of cells
-    for (int i = 0; i < cells->n; i++) {
-        pmCell *cell = cells->data[i];  // The cell of interest
-        success |= pmCellReadMask(cell, fits, db);
-    }
-    if (success) {
-        if (!pmConceptsReadChip(chip, PM_CONCEPT_SOURCE_HEADER, true, true, NULL)) {
-            psError(PS_ERR_IO, false, "Failed to read concepts for FPA.\n");
-            return false;
-        }
-        // XXX probably could just use chip->data_exists
-        pmChipSetDataStatus(chip, true);
-    }
-
-    return success;
+    return chipRead(chip, fits, db, FPA_READ_TYPE_MASK);
 }
 
@@ -508,20 +552,5 @@
     PS_ASSERT_PTR_NON_NULL(fits, false);
 
-    bool success = false;               // Were we able to read at least one HDU?
-    psArray *chips = fpa->chips;        // Array of chips
-    for (int i = 0; i < chips->n; i++) {
-        pmChip *chip = chips->data[i];  // The cell of interest
-        success |= pmChipReadMask(chip, fits, db);
-    }
-    if (success) {
-        if (!pmConceptsReadFPA(fpa, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
-            psError(PS_ERR_IO, false, "Failed to read concepts for FPA.\n");
-            return false;
-        }
-    } else {
-        psError(PS_ERR_UNKNOWN, false, "Unable to read any chips in FPA");
-    }
-
-    return success;
+    return fpaRead(fpa, fits, db, FPA_READ_TYPE_MASK);
 }
 
@@ -535,48 +564,5 @@
     PS_ASSERT_PTR_NON_NULL(fits, false);
 
-    pmHDU *hdu = pmHDUFromCell(cell);   // The HDU
-    if (!hdu) {
-        return false;                    // Nothing to see here; move along
-    }
-    if (!hdu->images && !pmHDURead(hdu, fits)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to read HDU for cell.\n");
-        return false;
-    }
-
-    if (!pmConceptsReadCell(cell, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
-        psError(PS_ERR_UNKNOWN, false, "Failed to read concepts for cell");
-        return false;
-    }
-
-    // Having read the cell, we now have to cut it up
-    psRegion *trimsec = psMetadataLookupPtr(NULL, cell->concepts, "CELL.TRIMSEC");
-
-    // Iterate over each of the image planes
-    for (int i = 0; i < hdu->images->n; i++) {
-        psImage *image = hdu->images->data[i]; // The i-th plane
-
-        if (image->type.type != PS_TYPE_F32) {
-            psImage *temp = psImageCopy(NULL, image, PS_TYPE_F32); // Temporary image
-            psFree(hdu->images->data[i]);
-            hdu->images->data[i] = temp;
-            image = temp;
-        }
-
-        pmReadout *readout;             // Readout into which to read
-        if (cell->readouts->n > i && cell->readouts->data[i]) {
-            readout = psMemIncrRefCounter(cell->readouts->data[i]);
-        } else {
-            readout = pmReadoutAlloc(cell);
-        }
-        if (!readoutCarve(readout, &readout->weight, image, trimsec, NULL)) {
-            psError(PS_ERR_UNEXPECTED_NULL, false,
-                    "Unable to carve readout into image and bias sections for %d the plane.", i);
-            return NULL;
-        }
-        psFree(readout);                // Drop reference
-    }
-
-    pmCellSetDataStatus(cell, true);
-    return true;
+    return cellRead(cell, fits, db, FPA_READ_TYPE_WEIGHT);
 }
 
@@ -586,20 +572,5 @@
     PS_ASSERT_PTR_NON_NULL(fits, false);
 
-    bool success = false;               // Were we able to read at least one HDU?
-    psArray *cells = chip->cells;       // Array of cells
-    for (int i = 0; i < cells->n; i++) {
-        pmCell *cell = cells->data[i];  // The cell of interest
-        success |= pmCellReadWeight(cell, fits, db);
-    }
-    if (success) {
-        if (!pmConceptsReadChip(chip, PM_CONCEPT_SOURCE_HEADER, true, true, NULL)) {
-            psError(PS_ERR_IO, false, "Failed to read concepts for FPA.\n");
-            return false;
-        }
-        // XXX probably could just use chip->data_exists
-        pmChipSetDataStatus(chip, true);
-    }
-
-    return success;
+    return chipRead(chip, fits, db, FPA_READ_TYPE_WEIGHT);
 }
 
@@ -609,22 +580,10 @@
     PS_ASSERT_PTR_NON_NULL(fits, false);
 
-    bool success = false;               // Were we able to read at least one HDU?
-    psArray *chips = fpa->chips;        // Array of chips
-    for (int i = 0; i < chips->n; i++) {
-        pmChip *chip = chips->data[i];  // The cell of interest
-        success |= pmChipReadWeight(chip, fits, db);
-    }
-    if (success) {
-        if (!pmConceptsReadFPA(fpa, PM_CONCEPT_SOURCE_HEADER, true, NULL)) {
-            psError(PS_ERR_IO, false, "Failed to read concepts for FPA.\n");
-            return false;
-        }
-    } else {
-        psError(PS_ERR_UNKNOWN, false, "Unable to read any chips in FPA");
-    }
-
-    return success;
-}
-
+    return fpaRead(fpa, fits, db, FPA_READ_TYPE_WEIGHT);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Reading FITS tables
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 int pmCellReadTable(pmCell *cell, psFits *fits, const char *name)
