Index: trunk/psModules/src/camera/pmFPAConstruct.c
===================================================================
--- trunk/psModules/src/camera/pmFPAConstruct.c	(revision 14471)
+++ trunk/psModules/src/camera/pmFPAConstruct.c	(revision 15068)
@@ -190,58 +190,36 @@
 // Looks up the particular content, based on the chip and cell
 static const char *getContent(const psMetadata *fileInfo, // The FILE from the camera format configuration
-                              const psMetadata *contents, // The CONTENTS from the camera format configuration
-                              const pmChip *chip, // The chip of interest
-                              const pmCell *cell // The cell of interest
+                              const psMetadata *header, // The FITS header
+                              const psMetadata *contents // The CONTENTS from the camera format configuration
                              )
 {
     assert(fileInfo);
     assert(contents);
-    assert(chip);
-
-    bool mdok = true;                   // Status of MD lookup
-    char *contentKey = psMetadataLookupStr(&mdok, fileInfo, "CONTENT"); // Key for CONTENTS
-    if (!mdok || !contentKey || strlen(contentKey) == 0) {
-        psError(PS_ERR_IO, true, "Unable to find CONTENT in FILE within camera format configuration.\n");
+    assert(header);
+
+    const char *contentHeader = psMetadataLookupStr(NULL, fileInfo, "CONTENT"); // Keyword to get contents
+    if (!contentHeader || strlen(contentHeader) == 0) {
+        psError(PS_ERR_UNEXPECTED_NULL, false,
+                "Unable to find CONTENT in FILE within camera format configuration.\n");
         return NULL;
     }
 
-    contentKey = psStringCopy(contentKey); // So that we're not altering something someone else might use...
-
-    // Replace some concept names
-    if (strstr(contentKey, "{CHIP.NAME}")) {
-        if (!chip) {
-            psError(PS_ERR_IO, true, "CONTENT in FILE refers to CHIP.NAME, but no chip was provided.\n");
-            psFree(contentKey);
-            return NULL;
-        }
-        const char *name = psMetadataLookupStr(&mdok, chip->concepts, "CHIP.NAME");
-        if (mdok && name && strlen(name) > 0) {
-            psStringSubstitute(&contentKey, name, "{CHIP.NAME}");
-        }
-    }
-
-    if (strstr(contentKey, "{CELL.NAME}")) {
-        if (!chip) {
-            psError(PS_ERR_IO, true, "CONTENT in FILE refers to CELL.NAME, but no chip was provided.\n");
-            psFree(contentKey);
-            return NULL;
-        }
-        const char *name = psMetadataLookupStr(&mdok, cell->concepts, "CELL.NAME");
-        if (mdok && name && strlen(name) > 0) {
-            psStringSubstitute(&contentKey, name, "{CELL.NAME}");
-        }
-    }
-
-    // XXX: MORE SUBSTITUTION OPTIONS HERE!
-
-    psTrace("psModules.camera", 5, "Looking up %s in the CONTENTS.\n", contentKey);
-    const char *content = psMetadataLookupStr(&mdok, contents, contentKey);
-    if (!mdok || !content || strlen(content) == 0) {
-        psFree(contentKey);
-        psError(PS_ERR_IO, true, "Unable to find %s in the CONTENTS.\n", contentKey);
+    psMetadataItem *contentKey = psMetadataLookup(header, contentHeader); // Key to CONTENTS menu
+    if (!contentKey) {
+        psError(PS_ERR_UNEXPECTED_NULL, false,
+                "Unable to find %s in header to determine file content.", contentHeader);
         return NULL;
     }
 
-    psFree(contentKey);
+    psString contentKeyStr = psMetadataItemParseString(contentKey); // Key, as a string
+
+    psTrace("psModules.camera", 5, "Looking up %s in the CONTENTS.\n", contentKeyStr);
+    const char *content = psMetadataLookupStr(NULL, contents, contentKeyStr);
+    if (!content || strlen(content) == 0) {
+        psError(PS_ERR_IO, false, "Unable to find %s in the CONTENTS.\n", contentKeyStr);
+        return NULL;
+    }
+
+    psFree(contentKeyStr);
 
     return content;
@@ -252,5 +230,4 @@
 static bool processContents(pmFPA *fpa,  // The FPA
                             pmChip *chip, // The chip
-                            pmCell *cell, // The cell
                             pmHDU *hdu,  // The HDU to be added
                             pmFPALevel level, // The level at which to add the HDU
@@ -265,5 +242,5 @@
     long num = cellTypes->n;            // Number of entries to add
     assert(chip || (chipNames && chipNames->n == num));
-    assert(cell || (cellNames && cellNames->n == num));
+    assert(cellNames && cellNames->n == num);
     assert(format);
 
@@ -310,16 +287,12 @@
         // Find the cell
         pmCell *newCell;                // Cell of interest
-        if (cell) {
-            newCell = cell;
-        } else {
-            psString cellName = cellNames->data[i]; // The name of the cell
-            int cellNum = pmChipFindCell(newChip, cellName); // The cell we're looking for
-            if (cellNum == -1) {
-                psError(PS_ERR_LOCATION_INVALID, false, "Unable to find cell %s in chip --- ignored.\n",
-                        cellName);
-                return false;
-            }
-            newCell = newChip->cells->data[cellNum];
-        }
+        psString cellName = cellNames->data[i]; // The name of the cell
+        int cellNum = pmChipFindCell(newChip, cellName); // The cell we're looking for
+        if (cellNum == -1) {
+            psError(PS_ERR_LOCATION_INVALID, false, "Unable to find cell %s in chip --- ignored.\n",
+                    cellName);
+            return false;
+        }
+        newCell = newChip->cells->data[cellNum];
 
         psMetadata *cellData = getCellData(format, cellType); // Data for this cell
@@ -380,65 +353,151 @@
 #endif
 
-// Find the chip of interest within the FPA, using either the view (simple) or the FITS header (bit more
-// complicated).  Also updates the provided view to point to the chip if we have to find it.
-static pmChip *whichChip(pmFPAview *view, // View to chip, modified
-                         const pmFPA *fpa, // FPA holding chip of interest
-                         const pmFPAview *phuView, // View to PHU, or NULL
-                         const psMetadata *fileInfo, // FILE information from camera format
-                         const psMetadata *header // FITS header, or NULL
-                         )
-{
-    assert(view);
+// Find the chip of interest within the FPA
+static bool whichChip(int *chipNum, // Chip number, modified
+                      psString *chipType, // Type of chip, modified
+                      const pmFPA *fpa, // FPA holding chip of interest
+                      const char *content // Content consisting of chipName:chipType
+                      )
+{
+    assert(chipType);
     assert(fpa);
-    assert(phuView || header);
-    assert(fileInfo);
-
-    if (phuView) {
-        return pmFPAviewThisChip(phuView, fpa);
-    }
-
-    psString chipName = phuNameFromHeader("CHIP.NAME", fileInfo, header);
+    assert(content);
+
+    psArray *chipNames = NULL;
+    psArray *chipTypes = NULL;
+    if (parseContent(&chipNames, &chipTypes, NULL, content) != 1) {
+        psError(PS_ERR_UNKNOWN, false,
+                "Unable to parse chipName:chipType in %s in camera format",
+                TABLE_OF_CONTENTS);
+        return false;
+    }
+
+    psString chipName = psMemIncrRefCounter(chipNames->data[0]); // Name of chip
+    *chipType = psMemIncrRefCounter(chipTypes->data[0]); // Type of chip
+    psFree(chipNames);
+    psFree(chipTypes);
+
     psTrace("psModules.camera", 5, "This is chip %s\n", chipName);
-    int chipNum = pmFPAFindChip(fpa, chipName); // Chip number
-    if (chipNum == -1) {
+
+    // Get the chip
+    *chipNum = pmFPAFindChip(fpa, chipName); // Chip number
+    if (*chipNum == -1) {
         psError(PS_ERR_UNKNOWN, true, "Unable to find chip %s in FPA.\n", chipName);
+        psFree(chipName);
+        return false;
+    }
+    psFree(chipName);
+
+    return true;
+}
+
+
+// Process a chip, using the cellName:cellType pair
+static bool processChip(const psMetadata *format, // Camera format
+                        const char *chipContents, // Contents of chip, cellName:cellType pairs
+                        pmFPA *fpa, // FPA of interest
+                        pmChip *chip, // Chip of interest
+                        pmHDU *hdu      // HDU to add
+                        )
+{
+    assert(format);
+    assert(chipContents);
+    assert(fpa);
+
+    psMetadata *chips = psMetadataLookupMetadata(NULL, format, CHIP_TYPES); // The chip types
+    if (!chips) {
+        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find %s in camera format.", CHIP_TYPES);
+        return false;
+    }
+
+    psArray *cellNames = NULL;      // Cell names
+    psArray *cellTypes = NULL;      // Cell types
+    if (parseContent(&cellNames, &cellTypes, NULL, chipContents) == 0) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                "Unable to parse chip contents (within %s in camera format) as cellName:cellType",
+                CHIP_TYPES);
+        psFree(cellNames);
+        psFree(cellTypes);
+        return false;
+    }
+
+    if (!processContents(fpa, chip, hdu, PM_FPA_LEVEL_CELL, NULL, cellNames, cellTypes, format)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to set contents for chip from camera format.");
+        psFree(cellNames);
+        psFree(cellTypes);
+        return false;
+    }
+
+    psFree(cellNames);
+    psFree(cellTypes);
+
+    return true;
+}
+
+// Given a chip, find the corresponding type by searching through the contents, looking for a match to its
+// name
+psString findChipType(const pmChip *chip, // Chip of interest
+                      psMetadata *contents // Contents, from camera format
+                      )
+{
+    assert(chip);
+    assert(contents);
+
+    const char *chipName = psMetadataLookupStr(NULL, chip->concepts, "CHIP.NAME"); // Name of chip
+    assert(chipName);
+
+    psString chipType = NULL;           // Type of chip
+    psMetadataIterator *iter = psMetadataIteratorAlloc(contents, PS_LIST_HEAD, NULL); // Iterator
+    psMetadataItem *item;           // Item from iteration
+    while ((item = psMetadataGetAndIncrement(iter))) {
+        if (item->type != PS_DATA_STRING) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                    "Item %s within %s in camera format is not of type STR.", item->name, TABLE_OF_CONTENTS);
+            psFree(iter);
+            psFree(chipType);
+            return NULL;
+        }
+
+        psArray *chipNames = NULL;  // Chip names
+        psArray *chipTypes = NULL;  // Chip types
+        if (parseContent(&chipNames, &chipTypes, NULL, item->data.str) != 1) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Unable to parse contents (within %s in camera format) as chipName:chipType",
+                    TABLE_OF_CONTENTS);
+            psFree(chipNames);
+            psFree(chipTypes);
+            psFree(iter);
+            psFree(chipType);
+            return NULL;
+        }
+
+        if (strcmp(chipName, chipNames->data[0]) == 0) {
+            if (chipType) {
+                if (strcmp(chipType, chipTypes->data[0]) != 0) {
+                    psError(PS_ERR_UNKNOWN, true,
+                            "Multiple instances of chip %s in contents, with differing chipType "
+                            "(%s vs %s)", chipName, chipType, (char*)chipTypes->data[0]);
+                    psFree(chipNames);
+                    psFree(chipTypes);
+                    psFree(iter);
+                    psFree(chipType);
+                    return NULL;
+                }
+            } else {
+                chipType = psMemIncrRefCounter(chipTypes->data[0]);
+            }
+        }
+        psFree(chipNames);
+        psFree(chipTypes);
+    }
+    psFree(iter);
+
+    if (!chipType) {
+        psError(PS_ERR_UNKNOWN, true, "Unable to identify chip type for chip %s", chipName);
         return NULL;
     }
-    psFree(chipName);
-    view->chip = chipNum;
-    return fpa->chips->data[chipNum];
-}
-
-// Find the cell of interest within the chip, using either the view (simple) or the FITS header (bit more
-// complicated).  Also updates the provided view to point to the cell if we have to find it.
-static pmCell *whichCell(pmFPAview *view, // View to cell
-                         const pmChip *chip, // Chip holding cell of interest
-                         const pmFPAview *phuView, // View to PHU, or NULL
-                         const psMetadata *fileInfo, // FILE information from camera format
-                         const psMetadata *header // FITS header, or NULL
-                         )
-{
-    assert(view);
-    assert(chip);
-    assert(phuView || header);
-    assert(fileInfo);
-
-    pmFPA *fpa = chip->parent;          // The parent FPA
-
-    if (phuView) {
-        return pmFPAviewThisCell(phuView, fpa);
-    }
-
-    psString cellName = phuNameFromHeader("CELL.NAME", fileInfo, header);
-    psTrace("psModules.camera", 5, "This is cell %s\n", cellName);
-    int cellNum = pmChipFindCell(chip, cellName); // Cell number
-    if (cellNum == -1) {
-        psError(PS_ERR_UNKNOWN, true, "Unable to find cell %s in chip.\n", cellName);
-        return NULL;
-    }
-    view->cell = cellNum;
-    return chip->cells->data[cellNum];
-}
-
+
+    return chipType;
+}
 
 // PHU=FPA and EXTENSIONS=CHIP:
@@ -484,74 +543,28 @@
         // What's in the extension?  It's specified by chipName:chipType
         // Assume that an extension contains only a single chip, instead of multiple chips
-
-        psString extContents = item->data.str; // Contents of extension
-        psArray *chipNames = NULL;
-        psArray *chipTypes = NULL;
-        if (parseContent(&chipNames, &chipTypes, NULL, extContents) != 1) {
-            psError(PS_ERR_UNKNOWN, false,
-                    "Unable to parse chipName:chipType in %s of %s in camera format",
-                    extname, TABLE_OF_CONTENTS);
-        }
-
-        psString chipName = psMemIncrRefCounter(chipNames->data[0]); // Name of chip
-        psString chipType = psMemIncrRefCounter(chipTypes->data[0]); // Type of chip
-        psFree(chipNames);
-        psFree(chipTypes);
-
-        // Get the chip
-        int chipNum = pmFPAFindChip(fpa, chipName); // Chip number
-        if (chipNum == -1) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to find chip %s in FPA.\n", chipName);
+        psString chipType = NULL;       // Type of chip
+        int chipNum = -1;               // Chip number
+        if (!whichChip(&chipNum, &chipType, fpa, item->data.str)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to determine chip from contents");
+            return false;
+        }
+        pmChip *chip = fpa->chips->data[chipNum]; // Chip of interest
+
+        const char *chipContents = psMetadataLookupStr(NULL, chips, chipType); // Contents of chip
+        psFree(chipType);
+        if (!chipContents) {
+            psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find chip type %s in %s.",
+                    chipType, CHIP_TYPES);
             psFree(hdu);
             psFree(contentsIter);
             return false;
         }
-        pmChip *chip = fpa->chips->data[chipNum]; // Chip of interest
-
-        // What's in the chip?
-
-        psString chipContents = psMetadataLookupStr(NULL, chips, chipType); // Contents of the chip
-        if (!chipContents) {
-            psError(PS_ERR_UNEXPECTED_NULL, false,
-                    "Unable to find chip type %s (for extension %s) in %s of camera format",
-                    chipType, extname, CHIP_TYPES);
-            psFree(chipName);
-            psFree(chipType);
+
+        if (!processChip(format, chipContents, fpa, chip, hdu)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to process chip %d\n", chipNum);
             psFree(hdu);
             psFree(contentsIter);
             return false;
         }
-
-        psArray *cellNames = NULL;      // Cell names
-        psArray *cellTypes = NULL;      // Cell types
-        if (parseContent(&cellNames, &cellTypes, NULL, chipContents) == 0) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Unable to parse chip contents (within %s->%s in camera format; for chip %s) "
-                    "as cellName:cellType", CHIP_TYPES, chipType, chipName);
-            psFree(cellNames);
-            psFree(cellTypes);
-            psFree(chipName);
-            psFree(chipType);
-            psFree(hdu);
-            psFree(contentsIter);
-            return false;
-        }
-
-        if (!processContents(fpa, chip, NULL, hdu, PM_FPA_LEVEL_CHIP, NULL, cellNames, cellTypes, format)) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to set contents for chip %s from camera format.",
-                    chipName);
-            psFree(cellNames);
-            psFree(cellTypes);
-            psFree(chipName);
-            psFree(chipType);
-            psFree(hdu);
-            psFree(contentsIter);
-            return false;
-        }
-
-        psFree(cellNames);
-        psFree(cellTypes);
-        psFree(chipName);
-        psFree(chipType);
 
         psFree(hdu);                    // Drop reference
@@ -612,5 +625,5 @@
         }
 
-        if (!processContents(fpa, NULL, NULL, hdu, PM_FPA_LEVEL_CELL, chipNames, cellNames, cellTypes,
+        if (!processContents(fpa, NULL, hdu, PM_FPA_LEVEL_CELL, chipNames, cellNames, cellTypes,
                              format)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to set contents from camera format.");
@@ -664,5 +677,5 @@
     }
 
-    if (!processContents(fpa, NULL, NULL, NULL, PM_FPA_LEVEL_NONE, chipNames, cellNames, cellTypes,
+    if (!processContents(fpa, NULL, NULL, PM_FPA_LEVEL_NONE, chipNames, cellNames, cellTypes,
                          format)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to set contents from camera format.");
@@ -682,12 +695,17 @@
 
 // PHU=CHIP and EXTENSIONS=CELL:
-// TABLE_OF_CONTENTS(METADATA) has a menu of contents, each with a chipType.
-// CHIP_TYPES(METADATA) has a list of chip types, each with extension(METADATA) with cellName:cellType
-static bool addSource_CHIP_CELL(pmChip *chip, // Chip to which to add
-                                const psMetadata *format // The camera format
+// TABLE_OF_CONTENTS(METADATA) has a menu of contents, each with a chipName:chipType.
+// CHIP_TYPES(METADATA) has a list of chip types(METADATA), each with extension(STR) with cellName:cellType
+static bool addSource_CHIP_CELL(pmFPAview *view, // View for PHU, modified
+                                pmFPA *fpa, // FPA to which to add
+                                pmChip *chip, // Known chip to which to add, or NULL
+                                const psMetadata *format, // The camera format
+                                pmHDU *phdu // The Primary HDU
                                 )
 {
-    assert(chip);
+    assert(view);
+    assert(fpa);
     assert(format);
+    assert(phdu);
 
     psMetadata *contents = psMetadataLookupMetadata(NULL, format, TABLE_OF_CONTENTS); // The contents
@@ -709,17 +727,36 @@
     }
 
-    const char *chipType = getContent(fileInfo, contents, chip, NULL); // The chip type
-
-    // What's in the chip?
-
-    psMetadata *chipContents = psMetadataLookupMetadata(NULL, chips, chipType); // Contents of the chip
+
+    psString chipType = NULL;           // Type of chip
+    if (chip) {
+        // We're given the chip (adding source from view)
+        // Need to identify the chip type, which we will do by traversing the contents
+        chipType = findChipType(chip, contents);
+    } else {
+        // We're given a header, from which to identify what chip we've got, and its type
+        const char *content = getContent(fileInfo, phdu->header, contents); // The contents of this chip
+
+        int chipNum = -1;               // Chip number
+        if (!whichChip(&chipNum, &chipType, fpa, content)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to determine chip from contents");
+            return false;
+        }
+        chip = fpa->chips->data[chipNum]; // Chip of interest
+        view->chip = chipNum;
+    }
+
+    if (!addHDUtoChip(chip, phdu)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to add HDU to chip\n");
+        psFree(chipType);
+        return false;
+    }
+
+    psMetadata *chipContents = psMetadataLookupMetadata(NULL, chips, chipType); // Contents of chip
+    psFree(chipType);
     if (!chipContents) {
-        psError(PS_ERR_UNEXPECTED_NULL, false,
-                "Unable to find chip type %s in %s of camera format",
+        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find chip type %s in %s.",
                 chipType, CHIP_TYPES);
         return false;
     }
-
-    pmFPA *fpa = chip->parent;          // The parent FPA
 
     psMetadataIterator *contentsIter = psMetadataIteratorAlloc(chipContents, PS_LIST_HEAD, NULL); // Iterator
@@ -740,12 +777,6 @@
         hdu->format = psMemIncrRefCounter((const psPtr)format);
 
-        psArray *cellNames = NULL;      // Cell names
-        psArray *cellTypes = NULL;      // Cell types
-        if (parseContent(&cellNames, &cellTypes, NULL, contentItem->data.str) == 0) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                    "Unable to parse chip contents (within %s->%s in camera format) "
-                    "as cellName:cellType", CHIP_TYPES, chipType);
-            psFree(cellNames);
-            psFree(cellTypes);
+        if (!processChip(format, contentItem->data.str, fpa, chip, hdu)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to process chip\n");
             psFree(hdu);
             psFree(contentsIter);
@@ -753,20 +784,12 @@
         }
 
-        if (!processContents(fpa, chip, NULL, hdu, PM_FPA_LEVEL_CELL, NULL, cellNames, cellTypes, format)) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to set contents for chip type %s from camera format.",
-                    chipType);
-            psFree(cellNames);
-            psFree(cellTypes);
-            psFree(hdu);
-            psFree(contentsIter);
-            return false;
-        }
-
-        psFree(cellNames);
-        psFree(cellTypes);
-
         psFree(hdu);                    // Drop reference
     }
     psFree(contentsIter);
+
+    if (!pmConceptsReadChip(chip, PM_CONCEPT_SOURCE_DEFAULTS | PM_CONCEPT_SOURCE_PHU, true, true, NULL)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to read concepts for chip.");
+        return false;
+    }
 
     return true;
@@ -776,10 +799,14 @@
 // TABLE_OF_CONTENTS(METADATA) has a menu of contents, each with a chipName:chipType.
 // CHIP_TYPES(METADATA) has a list of chip types, each with cellName:cellType
-static bool addSource_CHIP_NONE(pmChip *chip, // Chip to which to add
-                                const psMetadata *format // The camera format
+static bool addSource_CHIP_NONE(pmFPAview *view, // View for PHU, modified
+                                pmFPA *fpa, // FPA to which to add
+                                pmChip *chip, // Known chip to which to add, or NULL
+                                const psMetadata *format, // The camera format
+                                pmHDU *phdu // Primary HDU
                                 )
 {
-    assert(chip);
+    assert(fpa);
     assert(format);
+    assert(phdu);
 
     psMetadata *contents = psMetadataLookupMetadata(NULL, format, TABLE_OF_CONTENTS); // The contents
@@ -801,10 +828,28 @@
     }
 
-    pmFPA *fpa = chip->parent;          // Parent FPA
-
-    const char *chipType = getContent(fileInfo, contents, chip, NULL); // The chip type
+    psString chipType = NULL;           // Type of chip
+    if (chip) {
+        // We're given the chip (adding source from view)
+        // Need to identify the chip type, which we will do by traversing the contents
+        chipType = findChipType(chip, contents);
+    } else {
+        const char *content = getContent(fileInfo, phdu->header, contents); // The chip type
+
+        int chipNum = -1;               // Chip number
+        if (!whichChip(&chipNum, &chipType, fpa, content)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to determine chip from contents");
+            return false;
+        }
+        chip = fpa->chips->data[chipNum]; // Chip of interest
+        view->chip = chipNum;
+    }
+
+    if (!addHDUtoChip(chip, phdu)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to add HDU to chip\n");
+        psFree(chipType);
+        return false;
+    }
 
     // What's in the chip?
-
     psString chipContents = psMetadataLookupStr(NULL, chips, chipType); // Contents of the chip
     if (!chipContents) {
@@ -813,26 +858,15 @@
         return false;
     }
-
-    psArray *cellNames = NULL;      // Cell names
-    psArray *cellTypes = NULL;      // Cell types
-    if (parseContent(&cellNames, &cellTypes, NULL, chipContents) == 0) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "Unable to parse chip contents (within %s->%s in camera format) "
-                "as cellName:cellType", CHIP_TYPES, chipType);
-        psFree(cellNames);
-        psFree(cellTypes);
-        return false;
-    }
-
-    if (!processContents(fpa, chip, NULL, NULL, PM_FPA_LEVEL_NONE, NULL, cellNames, cellTypes, format)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to set contents for chip type %s from camera format.",
-                chipType);
-        psFree(cellNames);
-        psFree(cellTypes);
-        return false;
-    }
-
-    psFree(cellNames);
-    psFree(cellTypes);
+    psFree(chipType);
+
+    if (!processChip(format, chipContents, fpa, chip, NULL)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to process chip\n");
+        return false;
+    }
+
+    if (!pmConceptsReadChip(chip, PM_CONCEPT_SOURCE_DEFAULTS | PM_CONCEPT_SOURCE_PHU, true, true, NULL)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to read concepts for chip.");
+        return false;
+    }
 
     return true;
@@ -840,11 +874,15 @@
 
 // PHU=CELL and EXTENSIONS=NONE:
-// TABLE_OF_CONTENTS(METADATA) has a menu of contents, each with a cellName:cellType
-static bool addSource_CELL_NONE(pmCell *cell, // Cell to which to add
-                                const psMetadata *format // The camera format
+// TABLE_OF_CONTENTS(METADATA) has a menu of contents, each with a chipName:cellName:cellType
+static bool addSource_CELL_NONE(pmFPAview *view, // View for PHU, modified
+                                pmFPA *fpa, // FPA to which to add
+                                pmCell *cell, // Known cell to which to add, or NULL
+                                const psMetadata *format, // The camera format
+                                pmHDU *phdu // The Primary HDU
                                 )
 {
-    assert(cell);
+    assert(fpa);
     assert(format);
+    assert(phdu);
 
     psMetadata *contents = psMetadataLookupMetadata(NULL, format, TABLE_OF_CONTENTS); // The contents
@@ -860,21 +898,140 @@
     }
 
-    pmChip *chip = cell->parent;        // Parent chip
-    pmFPA *fpa = chip->parent;          // Parent FPA
-
-    const char *content = getContent(fileInfo, contents, chip, cell); // Content of cell
-
-    psArray *cellNames = NULL;      // Cell names
-    psArray *cellTypes = NULL;      // Cell types
-    if (parseContent(&cellNames, &cellTypes, NULL, content) != 1) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
-                "Unable to parse cell contents (%s) as cellName:cellType", content);
+    psArray *chipNames = NULL;          // Chip names
+    psArray *cellNames = NULL;          // Cell names
+    psArray *cellTypes = NULL;          // Cell types
+    pmChip *chip = NULL;                // Chip of interest
+    if (cell) {
+        // We're given the chip and cell (adding source from view)
+        // Need to identify the cell type, which we will do by traversing the contents
+
+        chip = cell->parent;            // The chip of interest
+        psString cellType = NULL;       // Type of cell
+
+        // The below is very similar to findChipType(), but with modifications for finding the cellType
+        const char *chipName = psMetadataLookupStr(NULL, chip->concepts, "CHIP.NAME"); // Name of chip
+        assert(chipName);
+        const char *cellName = psMetadataLookupStr(NULL, cell->concepts, "CELL.NAME"); // Name of cell
+        assert(cellName);
+
+        psMetadataIterator *iter = psMetadataIteratorAlloc(contents, PS_LIST_HEAD, NULL); // Iterator
+        psMetadataItem *item;           // Item from iteration
+        while ((item = psMetadataGetAndIncrement(iter))) {
+            if (item->type != PS_DATA_STRING) {
+                psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                        "Item %s within %s in camera format is not of type STR.",
+                        item->name, TABLE_OF_CONTENTS);
+                psFree(chipNames);
+                psFree(cellNames);
+                psFree(cellTypes);
+                psFree(iter);
+                psFree(cellType);
+                return false;
+            }
+
+            psArray *testChipNames = NULL; // Chip names
+            psArray *testCellNames = NULL; // Cell names
+            psArray *testCellTypes = NULL; // Cell types
+            if (parseContent(&testChipNames, &testCellTypes, &testCellTypes, item->data.str) != 1) {
+                psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                        "Unable to parse contents (within %s in camera format) as chipName:cellName:cellType",
+                        TABLE_OF_CONTENTS);
+                psFree(chipNames);
+                psFree(cellNames);
+                psFree(cellTypes);
+                psFree(testChipNames);
+                psFree(testCellNames);
+                psFree(testCellTypes);
+                psFree(iter);
+                psFree(cellType);
+                return false;
+            }
+
+            if (strcmp(chipName, chipNames->data[0]) == 0 && strcmp(cellName, cellNames->data[0]) == 0) {
+                if (cellType) {
+                    if (strcmp(cellType, cellTypes->data[0]) != 0) {
+                        psError(PS_ERR_UNKNOWN, true,
+                                "Multiple instances of chip %s cell %s in contents, with differing cellType "
+                                "(%s vs %s)", chipName, cellName, cellType, (char*)cellTypes->data[0]);
+                        psFree(chipNames);
+                        psFree(cellNames);
+                        psFree(cellTypes);
+                        psFree(testChipNames);
+                        psFree(testCellNames);
+                        psFree(testCellTypes);
+                        psFree(iter);
+                        psFree(cellType);
+                        return false;
+                    }
+                } else {
+                    cellType = psMemIncrRefCounter(cellTypes->data[0]);
+                    chipNames = psMemIncrRefCounter(testChipNames);
+                    cellNames = psMemIncrRefCounter(testCellNames);
+                    cellTypes = psMemIncrRefCounter(testCellTypes);
+                }
+            }
+            psFree(testChipNames);
+            psFree(testCellNames);
+            psFree(testCellTypes);
+        }
+        psFree(iter);
+
+        if (!cellType) {
+            psError(PS_ERR_UNKNOWN, true, "Unable to identify cell type for chip %s cell %s",
+                    chipName, cellName);
+            psFree(chipNames);
+            psFree(cellNames);
+            psFree(cellTypes);
+            return false;
+        }
+
+        // We don't really care about the cell type here --- it's taken care of by processContents
+        psFree(cellType);
+
+    } else {
+        const char *content = getContent(fileInfo, phdu->header, contents); // Content of cell
+
+        if (parseContent(&chipNames, &cellNames, &cellTypes, content) != 1) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Unable to parse cell contents (%s) as cellName:cellType", content);
+            psFree(chipNames);
+            psFree(cellNames);
+            psFree(cellTypes);
+            return false;
+        }
+
+        int chipNum = pmFPAFindChip(fpa, chipNames->data[0]); // Chip number
+        if (chipNum == -1) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to find chip %s referred to in contents",
+                    (char*)chipNames->data[0]);
+            psFree(chipNames);
+            psFree(cellNames);
+            psFree(cellTypes);
+            return false;
+        }
+        chip = fpa->chips->data[chipNum];
+
+        int cellNum = pmChipFindCell(chip, cellNames->data[0]); // Cell number
+        if (cellNum == -1) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to find cell %s referred to in contents",
+                    (char*)cellNames->data[0]);
+            psFree(chipNames);
+            psFree(cellNames);
+            psFree(cellTypes);
+            return false;
+        }
+        cell = chip->cells->data[cellNum];
+
+        view->chip = chipNum;
+        view->cell = cellNum;
+
+        psFree(chipNames);
         psFree(cellNames);
         psFree(cellTypes);
-        return false;
-    }
-
-    if (!processContents(fpa, chip, cell, NULL, PM_FPA_LEVEL_NONE, NULL, cellNames, cellTypes, format)) {
+    }
+
+    if (!processContents(fpa, NULL, phdu, PM_FPA_LEVEL_NONE, chipNames, cellNames, cellTypes, format)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to set contents for cell from camera format.");
+        psFree(chipNames);
         psFree(cellNames);
         psFree(cellTypes);
@@ -882,6 +1039,12 @@
     }
 
+    psFree(chipNames);
     psFree(cellNames);
     psFree(cellTypes);
+
+    if (!pmConceptsReadCell(cell, PM_CONCEPT_SOURCE_DEFAULTS | PM_CONCEPT_SOURCE_PHU, true, NULL)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to read concepts for cell.");
+        return false;
+    }
 
     return true;
@@ -941,5 +1104,5 @@
     pmFPAview *view = pmFPAviewAlloc(0); // View, to be returned
     if (phuView) {
-        // Copy the view, for the case where we're given a header.
+        // Copy the view, for the case where we're given a view.
         *view = *phuView;
     }
@@ -957,5 +1120,5 @@
     // Case    PHU     EXTENSIONS     Description
     // ====    ===     ==========     ===========
-    // 1.      FPA     CHIP           CONTENTS(METADATA) has a list of extensions, each with a chip type.
+    // 1.      FPA     CHIP           CONTENTS(METADATA) has a list of extensions, each with chipName:chipType
     //                                CHIPS(METADATA) has a list of chip types, each with cell:type
     // 2.      FPA     CELL           CONTENTS(METADATA) has a list of extensions, each with chip:cell:type
@@ -963,10 +1126,10 @@
     // 3.      FPA     NONE           CONTENTS(STRING) has a list of extensions, chip:cell:type
     //                                No need for CHIPS
-    // 4.      CHIP    CELL           CONTENTS(METADATA) is a menu, each with a chip type
+    // 4.      CHIP    CELL           CONTENTS(METADATA) is a menu, each with a chipName:chipType
     //                                CHIPS(METADATA) has a list of chip types(METADATA), containg a list of
     //                                extensions.
-    // 5.      CHIP    NONE           CONTENTS(METADATA) is a menu, each with a chip type
+    // 5.      CHIP    NONE           CONTENTS(METADATA) is a menu, each with a chipName:chipType
     //                                CHIPS(METADATA) has a list of chip types(STRING) with cell:type
-    // 6.      CELL    NONE           CONTENTS(METADATA) is a menu, each with a cell type.
+    // 6.      CELL    NONE           CONTENTS(METADATA) is a menu, each with a chipName:cellName:cellType.
     //                                No need for CHIPS.
 
@@ -1032,11 +1195,7 @@
       }
       case PM_FPA_LEVEL_CHIP: {
-          // Which chip is our PHU?
-          pmChip *chip = whichChip(view, fpa, phuView, fileInfo, header); // Chip of interest
-          if (!chip) {
-              psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find chip to add.");
-              psFree(phdu);
-              psFree(view);
-              return NULL;
+          pmChip *chip = NULL;          // Appropriate chip, if the view is specified
+          if (phuView) {
+              chip = fpa->chips->data[phuView->chip];
           }
           switch (extLevel) {
@@ -1044,7 +1203,5 @@
               if (install) {
                   phdu->blankPHU = true;
-                  if (!addHDUtoChip(chip, phdu) || !addSource_CHIP_CELL(chip, format) ||
-                      !pmConceptsReadChip(chip, PM_CONCEPT_SOURCE_DEFAULTS | PM_CONCEPT_SOURCE_PHU,
-                                          true, true, NULL)) {
+                  if (!addSource_CHIP_CELL(view, fpa, chip, format, phdu)) {
                       psError(PS_ERR_UNKNOWN, false, "Unable to add source.");
                       psFree(phdu);
@@ -1058,7 +1215,5 @@
               if (install) {
                   phdu->blankPHU = false;
-                  if (!addHDUtoChip(chip, phdu) || !addSource_CHIP_NONE(chip, format) ||
-                      !pmConceptsReadChip(chip, PM_CONCEPT_SOURCE_DEFAULTS | PM_CONCEPT_SOURCE_PHU,
-                                          true, true, NULL)) {
+                  if (!addSource_CHIP_NONE(view, fpa, chip, format, phdu)) {
                       psError(PS_ERR_UNKNOWN, false, "Unable to add source.");
                       psFree(phdu);
@@ -1077,18 +1232,4 @@
       }
       case PM_FPA_LEVEL_CELL: {
-          pmChip *chip = whichChip(view, fpa, phuView, fileInfo, header); // Chip of interest
-          if (!chip) {
-              psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find chip to add.");
-              psFree(phdu);
-              psFree(view);
-              return NULL;
-          }
-          pmCell *cell = whichCell(view, chip, phuView, fileInfo, header); // Cell of interest
-          if (!cell) {
-              psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find cell to add.");
-              psFree(phdu);
-              psFree(view);
-              return NULL;
-          }
           if (extLevel != PM_FPA_LEVEL_NONE) {
               psError(PS_ERR_BAD_PARAMETER_VALUE, true,
@@ -1096,9 +1237,13 @@
               return NULL;
           }
+          pmChip *chip = NULL;          // Appropriate chip, if the view is specified
+          pmCell *cell = NULL;          // Appropriate cell, if the view is specified
+          if (phuView) {
+              chip = fpa->chips->data[phuView->chip];
+              cell = chip->cells->data[phuView->cell];
+          }
           if (install) {
               phdu->blankPHU = false;
-              if (!addHDUtoCell(cell, phdu) || !addSource_CELL_NONE(cell, format) ||
-                  !pmConceptsReadCell(cell, PM_CONCEPT_SOURCE_DEFAULTS | PM_CONCEPT_SOURCE_PHU,
-                                      true, NULL)) {
+              if (!addSource_CELL_NONE(view, fpa, cell, format, phdu)) {
                   psError(PS_ERR_UNKNOWN, false, "Unable to add source.");
                   psFree(phdu);
