Index: /trunk/archive/scripts/src/pmFPAConstruct.c
===================================================================
--- /trunk/archive/scripts/src/pmFPAConstruct.c	(revision 4594)
+++ /trunk/archive/scripts/src/pmFPAConstruct.c	(revision 4594)
@@ -0,0 +1,308 @@
+#include <stdio.h>
+#include <string.h>
+#include "pslib.h"
+#include "papmodule.h"
+#include "papStuff.h"
+#include "papFocalPlane.h"
+#include "pmFPAConstruct.h"
+
+// NOTE: Need to deal with header inheritance
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// File-static functions
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Copy metadata elements into another metadata
+static void metadataCopy(psMetadata *to, // Metadata to which to copy
+			 psMetadata *from // Metdata from which to copy
+    )
+{
+    psMetadataIterator *mdIter = psMetadataIteratorAlloc(from, PS_LIST_HEAD, NULL); // Iterator for the MD
+    psMetadataItem *item = NULL;	// Item from the metadata
+    while (item = psMetadataGetAndIncrement(mdIter)) {
+	psTrace(__func__, 9, "Adding %s to metadata...\n", item->name);
+	if (! psMetadataAddItem(to, item, PS_LIST_TAIL, PS_META_REPLACE)) {
+	    psLogMsg(__func__, PS_LOG_WARN, "Unable to add item (%s: %s) to metadata: ignored\n", item->name,
+		     item->comment);
+	}
+    }
+    psFree(mdIter);
+}
+
+// Read data for a particular cell from the camera configuration
+static psMetadata *getCellData(const psMetadata *camera, // The camera configuration
+			       const char *cellName // The name of the cell
+    )
+{
+    bool status = true;			// Result of MD lookup
+    psMetadata *cells = psMetadataLookupMD(&status, camera, "CELLS"); // The CELLS
+    if (! status) {
+	psError(PS_ERR_IO, false, "Unable to determine CELLS of camera.\n");
+	return NULL;
+    }
+
+    psMetadata *cellData = psMetadataLookupMD(&status, cells, cellName); // The data for the particular cell
+    if (! status) {
+	psError(PS_ERR_IO, false, "Unable to find specs for cell %s: ignored\n", cellName);
+	return NULL;
+    } else {
+	return cellData;
+    }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Public functions
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+papFPA *pmFPAConstruct(const psMetadata *camera, // The camera configuration
+		       psDB *db		// Database handle
+    )
+{
+    papFPA *fpa = papFPAAlloc(camera, db); // The FPA to fill out
+    bool mdStatus = true;		// Status from metadata lookups
+    const char *phuType = psMetadataLookupString(&mdStatus, camera, "PHU"); // What is the PHU?
+    const char *extType = psMetadataLookupString(&mdStatus, camera, "EXTENSIONS"); // What's in the extensions?
+    if (strncmp(phuType, "FPA", 3) == 0) {
+	// The FITS file contains an entire FPA
+
+	psMetadata *contents = psMetadataLookupMD(&mdStatus, camera, "CONTENTS"); // The CONTENTS
+	if (! mdStatus) {
+	    psError(PS_ERR_IO, false, "Unable to determine CONTENTS of camera.\n");
+	    psFree(fpa);
+	    return NULL;
+	}
+
+	// Set up iteration over the contents
+	psMetadataIterator *contentsIter = psMetadataIteratorAlloc(contents, PS_LIST_HEAD, NULL);
+	psMetadataItem *contentItem = NULL; // Item from the metadata
+
+	if (strncmp(extType, "CHIP", 4) == 0) {
+	    // Extensions are chips; Content contains a list of cells
+	    while (contentItem = psMetadataGetAndIncrement(contentsIter)) {
+		const char *extName = contentItem->name; // The name of the extension
+		papChip *chip = papChipAlloc(fpa); // The chip
+		chip->extname = extName;// Mark chip to receive FITS data
+		if (contentItem->type != PS_META_STR) {
+		    psLogMsg(__func__, PS_LOG_WARN, "Type of content item (%x) is not string: ignored\n",
+			     contentItem->type);
+		    continue;
+		}
+
+		const char *content = contentItem->data.V; // The content of the extension
+		psTrace(__func__, 7, "Content of %s is: %s\n", extName, content);
+		psList *cellNames = papSplit(content, " ,"); // A list of the component cells
+		psListIterator *cellNamesIter = psListIteratorAlloc(cellNames, PS_LIST_HEAD, NULL);
+		char *cellName = NULL; // The name of a cell
+		while (cellName = psListGetAndIncrement(cellNamesIter)) {
+		    // Get the cell data
+		    papCell *cell = papCellAlloc(chip); // The cell
+		    psMetadata *cellData = getCellData(camera, cellName);
+		    metadataCopy(cell->values, cellData);
+		}
+		psFree(cellNamesIter);
+		psFree(cellNames);
+	    }
+
+	} else if (strncmp(extType, "CELL", 4) == 0) {
+	    // Extensions are cells; Content contains a chip name and cell type
+	    psMetadata *chips = psMetadataAlloc(); // Given a chip name, holds the chip number
+	    while (contentItem = psMetadataGetAndIncrement(contentsIter)) {
+		const char *extName = contentItem->name; // The name of the extension
+		psTrace(__func__, 1, "Getting %s....\n", extName);
+
+		if (contentItem->type != PS_META_STR) {
+		    psLogMsg(__func__, PS_LOG_WARN, "Type of content item (%x) is not string: ignored\n",
+			     contentItem->type);
+		    continue;
+		}
+		const char *content = contentItem->data.V; // The content of the extension
+		psList *contents = papSplit(content, ": "); // Split the name from the type
+		if (contents->size != 2) {
+		    psLogMsg(__func__, PS_LOG_WARN, "Unable to read contents of %s: ignored.\n", extName);
+		} else {
+		    const char *chipName = psListGet(contents, 0); // The name of the chip
+		    const char *cellType = psListGet(contents, 1); // The type of cell
+		    psTrace(__func__, 7, "Extension is cell of type %s, from chip %s\n", cellType,
+			    chipName);
+		    
+		    papChip *chip = psMetadataLookupChip(&mdStatus, chips, chipName); // The chip
+		    if (! mdStatus && ! chip) {
+			chip = papChipAlloc(fpa);
+			psMetadataAdd(chips, PS_LIST_TAIL, chipName, PS_META_CHIP, "", chip);
+		    }
+		    // The cell
+		    psArray *images = NULL;
+		    psMetadata *header = NULL;
+		    papCell *cell = papCellAlloc(chip); // The cell
+		    cell->extname = extName; // Mark cell to receive FITS data
+		    psMetadata *cellData = getCellData(camera, cellType);
+		    metadataCopy(cell->values, cellData);
+		}
+	    }
+	    psFree(chips);
+
+	} else if (strncmp(extType, "NONE", 4) == 0) {
+	    // No extensions; Content contains metadata, each entry is a chip with its component cells
+	    fpa->extname = "PHU";
+	    while (contentItem = psMetadataGetAndIncrement(contentsIter)) {
+		const char *chipName = contentItem->name; // The name of the chip
+
+		if (contentItem->type != PS_META_STR) {
+		    psLogMsg(__func__, PS_LOG_WARN, "Type of content item (%x) is not string: ignored\n",
+			     contentItem->type);
+		    continue;
+		}
+		const char *content = contentItem->data.V; // The content of the extension
+		psTrace(__func__, 5, "Component cells are: %s\n", content);
+		papChip *chip = papChipAlloc(fpa); // The chip
+		psList *cellNames = papSplit(content, ", "); // Split the list of cells
+		psListIterator *cellNamesIter = psListIteratorAlloc(cellNames, PS_LIST_HEAD, false);
+		char *cellName = NULL; // Name of the cell
+		while (cellName = psListGetAndIncrement(cellNamesIter)) {
+		    psTrace(__func__, 7, "Processing cell %s....\n", cellName);
+		    papCell *cell = papCellAlloc(chip); // The cell
+		    psMetadata *cellData = getCellData(camera, cellName);
+		    metadataCopy(cell->values, cellData);
+		}
+		psFree(cellNamesIter);
+	    }
+
+	} else {
+	    psError(PS_ERR_IO, false, "EXTENSIONS in camera definition is not CHIP, CELL or NONE.\n");
+	    psFree(fpa);
+	    return NULL;
+	} // Type of extension
+
+	psFree(contentsIter);
+
+    } else if (strncmp(phuType, "CHIP", 4) == 0) {
+	// The FITS file contains a single chip only
+	papChip *chip = papChipAlloc(fpa); // The chip
+
+	if (strncmp(extType, "NONE", 4) == 0) {
+	    // There are no extensions --- only the PHU
+	    chip->extname = "PHU";
+
+	    const char *contents = psMetadataLookupString(&mdStatus, camera, "CONTENTS");
+	    if (! mdStatus) {
+		psError(PS_ERR_IO, false, "Unable to determine CONTENTS of camera.\n");
+		psFree(fpa);
+		return NULL;
+	    }
+	    psList *cellNames = papSplit(contents, " ,"); // Names of cells
+	    psListIterator *cellIter = psListIteratorAlloc(cellNames, PS_LIST_HEAD, false); // Iterator
+	    const char *cellName = NULL;
+	    while (cellName = psListGetAndIncrement(cellIter)) {
+		papCell *cell = papCellAlloc(chip); // The cell
+		psMetadata *cellData = getCellData(camera, cellName);
+		metadataCopy(cell->values, cellData);
+	    }
+	    psFree(cellIter);
+
+	} else if (strncmp(extType, "CELL", 4) == 0) {
+	    // Extensions are cells
+	    psMetadata *contents = psMetadataLookupMD(&mdStatus, camera, "CONTENTS"); // The CONTENTS
+	    if (! mdStatus) {
+		psError(PS_ERR_IO, false, "Unable to determine CONTENTS of camera.\n");
+		psFree(fpa);
+		return NULL;
+	    }
+	    
+	    if (strncmp(extType, "CELL", 4) != 0) {
+		psLogMsg(__func__, PS_LOG_WARN, "EXTENSIONS in camera definition is %s, but PHU is CHIP.\n"
+			 "EXTENSIONS assumed to be CELL.\n", extType);
+	    }
+
+	    // Iterate through the contents
+	    psMetadataIterator *contentsIter = psMetadataIteratorAlloc(contents, PS_LIST_HEAD, NULL);
+	    psMetadataItem *contentItem = NULL; // Item from metadata
+	    while (contentItem = psMetadataGetAndIncrement(contentsIter)) {
+		const char *extName = contentItem->name; // The name of the extension
+
+		psMemCheckCorruption(true);
+		
+		psTrace(__func__, 1, "Getting %s....\n", extName);
+
+		// Content is a cell type
+		if (contentItem->type != PS_META_STR) {
+		    psLogMsg(__func__, PS_LOG_WARN,
+			     "CONTENT metadata for extension %s is not of type string, but %x --- ignored\n",
+			     extName, contentItem->type);
+		    continue;
+		}
+		const char *cellType = contentItem->data.V; // The type of cell
+		psTrace(__func__, 2, "Cell type is %s\n", cellType);
+		psArray *images = NULL;
+		psMetadata *header = NULL;
+		papCell *cell = papCellAlloc(chip); // The cell
+		cell->extname = extName; // Mark cell to receive FITS data
+		psMetadata *cellData = getCellData(camera, cellType);
+		metadataCopy(cell->values, cellData);
+
+	    } // Iterating through contents
+	    psFree(contentsIter);
+
+	} else {
+	    psError(PS_ERR_IO, false, "EXTENSIONS in camera definition is neither CELL or NONE.\n");
+	    psFree(fpa);
+	    return NULL;
+	}
+
+    } else {
+	psError(PS_ERR_IO, true,
+		"The PHU type specified in the camera configuration (%s) is not FPA or CHIP.\n",
+		phuType);
+	psFree(fpa);
+	return NULL;
+    }
+
+    return fpa;
+}
+
+// Print out the focal plane structure
+void pmFPAPrint(papFPA *fpa		// FPA to print
+    )
+{
+    psTrace(__func__, 0, "FPA:\n");
+    if (fpa->pixels) {
+	psTrace(__func__, 1, "---> FPA contains pixels.\n");
+    }
+
+    psArray *chips = fpa->chips;	// Array of chips
+    // Iterate over the FPA
+    for (int i = 0; i < chips->n; i++) {
+	psTrace(__func__, 1, "Chip: %d\n", i);
+	papChip *chip = chips->data[i]; // The chip
+	if (chip->pixels) {
+	    psTrace(__func__, 2, "---> Chip contains pixels.\n");
+	}
+	// Iterate over the chip
+	psArray *cells = chip->cells;	// Array of cells
+	for (int j = 0; j < cells->n; j++) {
+	    psTrace(__func__, 2, "Cell: %d\n", j);
+	    papCell *cell = cells->data[j]; // The cell
+	    if (cell->pixels) {
+		psTrace(__func__, 3, "---> Cell contains pixels.\n");
+	    }
+	    psMetadataPrint(cell->values, 3);
+	    psTrace(__func__, 3, "Readouts:\n");
+	    psArray *readouts = cell->readouts;	// Array of readouts
+	    for (int k = 0; k < readouts->n; k++) {
+		papReadout *readout = readouts->data[k]; // The readout
+		psImage *image = readout->image; // The image
+		psTrace(__func__, 4, "Image: [%d:%d,%d:%d]\n", image->col0, image->col0 + 
+			image->numCols, image->row0, image->row0 + image->numRows);
+		psList *overscans = readout->overscans;	// The list of overscans
+		psListIterator *overscansIter = psListIteratorAlloc(overscans, PS_LIST_HEAD, false);
+		while (image = psListGetAndIncrement(overscansIter)) {
+		    psTrace(__func__, 4, "Overscan: [%d:%d,%d:%d]\n", image->col0, image->col0 + 
+			    image->numCols, image->row0, image->row0 + image->numRows);
+		}
+		psFree(overscansIter);
+
+	    } // Iterating over cell
+	} // Iterating over chip
+    } // Iterating over FPA
+
+}
Index: /trunk/archive/scripts/src/pmFPAConstruct.h
===================================================================
--- /trunk/archive/scripts/src/pmFPAConstruct.h	(revision 4594)
+++ /trunk/archive/scripts/src/pmFPAConstruct.h	(revision 4594)
@@ -0,0 +1,17 @@
+#ifndef PM_FPA_CONSTRUCT_H
+#define PM_FPA_CONSTRUCT_H
+
+#include "pslib.h"
+#include "papFocalPlane.h"
+
+// Read the contents of a FITS file (format specified by the camera configuration) into memory
+papFPA *pmFPAConstruct(const psMetadata *camera, // The camera configuration
+		       psDB *db		// Database handle
+    );
+
+// Print out the FPA
+void pmFPAPrint(papFPA *fpa		// FPA to print
+    );
+
+
+#endif
