Index: /branches/rel10_ifa/psModules/src/astrom/pmHDU.c
===================================================================
--- /branches/rel10_ifa/psModules/src/astrom/pmHDU.c	(revision 6517)
+++ /branches/rel10_ifa/psModules/src/astrom/pmHDU.c	(revision 6517)
@@ -0,0 +1,255 @@
+#include <stdio.h>
+#include <assert.h>
+
+#include "pslib.h"
+#include "pmFPA.h"
+
+
+static void hduFree(pmHDU *hdu)
+{
+    psFree(hdu->extname);
+    psFree(hdu->header);
+    psFree(hdu->images);
+    psFree(hdu->table);
+}
+
+
+pmHDU *pmHDUAlloc(const char *extname   // Extension name
+                 )
+{
+    pmHDU *hdu = psAlloc(sizeof(pmHDU));
+    psMemSetDeallocator(hdu, (psFreeFunc)hduFree);
+
+    if (! extname || strlen(extname) == 0) {
+        hdu->phu = true;
+        hdu->extname = psStringCopy("PHU");
+    } else {
+        if (strcasecmp(extname, "PHU") == 0) {
+            hdu->phu = true;
+        } else {
+            hdu->phu = false;
+        }
+        hdu->extname = psStringCopy(extname);
+    }
+    hdu->header = NULL;
+    hdu->images = NULL;
+    hdu->table  = NULL;
+
+    return file;
+}
+
+// Read the HDU
+// XXX: Add a region specifier?
+bool pmHDURead(pmHDU *hdu,              // HDU to read
+               psFits *fits             // FITS file to read from
+              )
+{
+    assert(hdu);
+    assert(fits);
+
+    // Move to the appropriate extension
+    if (strcasecmp(hdu->extname, "PHU") == 0) {
+        if (! psFitsMoveExtNum(fits, 0, false)) {
+            psError(PS_ERR_IO, false, "Unable to move to primary header!\n");
+            return false;
+        }
+    } else if (! psFitsMoveExtName(fits, hdu->extname)) {
+        psError(PS_ERR_IO, false, "Unable to move to extension %s\n", hdu->extname);
+    }
+
+    // Read the header
+    if (! hdu->header) {
+        hdu->header = psFitsReadHeader(NULL, fits);
+    }
+
+    // What type is it?
+    if (psFitsIsImage(hdu->header)) {
+        if (hdu->images) {
+            psFree(hdu->images);        // Blow away anything existing
+        }
+        hdu->images = psFitsReadImageCube(fits, psRegionSet(0,0,0,0));
+        return true;
+    }
+    if (psFitsIsTable(hdu->table)) {
+        // Read the table
+        if (hdu->table) {
+            psFree(hdu->table);         // Blow away anything existing
+        }
+        hdu->table = psFitsReadTable(fits);
+        return true;
+    }
+
+    psError(PS_ERR_UNKNOWN, true, "No idea what this HDU consists of!\n");
+    return false;
+}
+
+// Write the HDU
+// XXX: Add a region specifier?
+bool pmHDUWrite(pmHDU *hdu,             // HDU to write
+                psFits *fits            // FITS file to write to
+               )
+{
+    assert(hdu);
+    assert(fits);
+
+    if (hdu->images && hdu->table && !hdu->header) {
+        psError(PS_ERR_IO, true, "Both image and table data provided in HDU, but no header --- "
+                "don't know which to write!\n");
+        return false;
+    }
+
+    if (hdu->images && (!hdu->table || psFitsIsImage(hdu->header))) {
+        psFitsWriteImageCube(fits, hdu->header, hdu->images, hdu->extname);
+        return true;
+    }
+
+    if (hdu->table && (!hdu->images || psFitsIsTable(hdu->header))) {
+        bool psFitsWriteTable(psFits* fits, const psMetadata *header, const psArray* table);
+        return true;
+    }
+
+    psError(PS_ERR_IO, true, "No idea what this HDU consists of!\n");
+    return false;
+}
+
+
+pmHDU *pmHDUFromFPA(pmFPA *fpa          // FPA for which to find HDU
+                   )
+{
+    pmHDU *hdu = fpa->hdu;              // The HDU information
+    if (!hdu) {
+        psError(PS_ERR_IO, true, "Unable to find HDU in chip.\n");
+        return NULL;
+    }
+
+    return hdu;
+}
+
+pmHDU *pmHDUFromChip(pmChip *chip       // Chip for which to find HDU
+                    )
+{
+    pmHDU *hdu = chip->hdu;             // The HDU information
+    if (!hdu) {
+        // Grab HDU info from the FPA
+        hdu = pmHDUFromFPA(chip->parent);
+        if (!hdu) {
+            psError(PS_ERR_IO, true, "Unable to find HDU in chip.\n");
+            return NULL;
+        }
+    }
+
+    return hdu;
+}
+
+pmHDU *pmHDUFromCell(pmCell *cell       // Cell for which to find HDU
+                    )
+{
+    pmHDU *hdu = cell->hdu;             // The HDU information
+    if (!hdu) {
+        // Grab HDU info from the chip
+        hdu = pmHDUFromChip(cell->parent);
+        if (!hdu) {
+            psError(PS_ERR_IO, true, "Unable to find HDU in cell.\n");
+            return NULL;
+        }
+    }
+
+    return hdu;
+}
+
+
+
+
+#if 0
+
+
+
+
+// Read the PHU of a file
+static bool readPHU(pmCameraFile *file  // File for which to read the PHU
+                   )
+{
+    if (! file->phu) {
+        if (! file->fits) {
+            file->fits = psFitsOpen(file->name, "r");
+        }
+        (void)psFitsMoveExtNum(file->fits, 0, false);
+        file->phu = psFitsReadHeader(NULL, file->fits);
+
+        return true;
+    }
+
+    return false;
+}
+
+bool pmCameraFileFormat(pmCameraFile *file, // File to inspect
+                        psMetadata *camera // Camera description
+                       )
+{
+    if (! camera) {
+        return false;
+    }
+
+    readPHU(file);
+
+    bool mdok = true;                   // Result of MD lookup
+    psMetadata *formats = psMetadataLookupMD(&mdok, camera, "FORMATS"); // List of known formats
+    if (! mdok || ! formats) {
+        psLogMsg(__func__, PS_LOG_WARN, "Unable to find list of FORMATS in camera configuration!\n");
+        return false;
+    }
+
+    bool result = false;                // Result of search
+    psMetadataIterator *formatsIter = psMetadataIteratorAlloc(formats, NULL); // Iterator for formats
+    psMetadataItem *formatsItem = NULL; // Item from formats
+    while ((formatsItem = psMetadataGetAndIncrement(formatsIter))) {
+        if (formatsItem->type != PS_DATA_STRING) {
+            psLogMsg(__func__, PS_LOG_WARN, "Entry not of type STR found in camera FORMATS list.\n");
+            continue;
+        }
+        psTrace(__func__, 7, "Trying format file: %s\n", formatsItem->name);
+        int numBadLines = 0;            // Number of bad lines in file
+        psMetadata *format = psMetadataConfigParse(NULL, &numBadLines, formatsItem->data.V, true);
+        if (numBadLines > 0) {
+            psLogMsg(__func__, PS_LOG_WARN, "%d bad lines found in %s.\n", formatsItem->name);
+        }
+        if (pmConfigValidateCamera(format, file->phu)) {
+            file->format = format;
+            result = true;
+            psLogMsg(__func__, PS_LOG_INFO + 2, "File %s matches camera format file %s\n", file->name,
+                     formatsItem->data.V);
+            break;
+        }
+        psFree(format);
+    }
+    psFree(formatsIter);
+
+    return result;
+}
+
+
+bool pmConfigValidateCamera(const psMetadata *camera, const psMetadata *header);
+
+pmFPA *pmFPASourceFile(pmFPA *fpa,      // FPA to which to add
+                       pmFile *file,    // File to add
+                       const char *name, // Symbolic name for file, e.g., "INPUT", "OUTPUT", "TESTFILE"
+                       pmConfig *config // Configuration set
+                      )
+{
+    assert(file);
+    assert(name);
+
+    if (! file->fits) {
+        file->fits = psFitsOpen(file->name, "r");
+    }
+    if (! file->phu) {
+        (void)psFitsMoveExtNum(file->fits, 0, false);
+        file->phu = psFitsReadHeader(NULL, file->fits);
+    }
+
+    psMetadata *fileConfig = NULL;      // The file configuration
+    if (fpa && fpa->camera) {
+        fpa
+
+        bool pmConfigValidateCamera(const psMetadata *camera, const psMetadata *header);
+        #endif
Index: /branches/rel10_ifa/psModules/src/astrom/pmHDU.h
===================================================================
--- /branches/rel10_ifa/psModules/src/astrom/pmHDU.h	(revision 6517)
+++ /branches/rel10_ifa/psModules/src/astrom/pmHDU.h	(revision 6517)
@@ -0,0 +1,34 @@
+#ifndef PM_HDU_H
+#define PM_HDU_H
+
+#include "pslib.h"
+#include "pmFPA.h"
+
+// An instance of the FITS Header Data Unit
+typedef struct
+{
+    psString extname;                   // The extension name
+    bool phu;                           // Is this the FITS Primary Header Unit
+    psMetadata *header;                 // The FITS header, or NULL if primary for FITS; or section info
+    psArray *images;                    // The pixel data
+    psArray *table;                     // The table data
+}
+pmHDU;
+
+
+// Allocators
+pmHDU *pmHDUAlloc(const char *extname);
+
+// Read the HDU
+bool pmHDURead(pmHDU *hdu);
+
+
+// Find the HDU in the FPA hierarchy
+pmHDU *pmHDUFromFPA(pmFPA *fpa          // FPA for which to find HDU
+                   );
+pmHDU *pmHDUFromChip(pmChip *chip       // Chip for which to find HDU
+                    );
+pmHDU *pmHDUFromCell(pmCell *cell       // Cell for which to find HDU
+                    );
+
+#endif
