Index: trunk/psModules/src/concepts/pmConceptsRead.c
===================================================================
--- trunk/psModules/src/concepts/pmConceptsRead.c	(revision 20868)
+++ trunk/psModules/src/concepts/pmConceptsRead.c	(revision 22699)
@@ -15,4 +15,6 @@
 #include "pmHDUUtils.h"
 #include "pmConcepts.h"
+#include "pmConceptsUpdate.h"
+
 #include "pmConceptsRead.h"
 
@@ -483,2 +485,193 @@
 }
 
+
+
+// Read all registered concepts for the specified level
+static bool conceptsRead(psMetadata **specs, // One of the concepts specifications
+                         pmFPA *fpa,    // The FPA
+                         pmChip *chip,  // The chip
+                         pmCell *cell, // The cell
+                         unsigned int *read,     // What's already been read
+                         pmConceptSource source, // The source of the concepts to read
+                         pmConfig *config, // Configuration
+                         psMetadata *target // Place into which to read the concepts
+                        )
+{
+    assert(specs);
+    assert(read);
+    assert(target);
+
+    pmConceptsInit();
+
+    // At least one HDU is required for the reading functions
+    pmHDU *hduLow = pmHDUGetLowest(fpa, chip, cell); // Lowest HDU.
+    if (!hduLow) {
+        // Can't do anything --- don't record any success, but don't return an error either
+        return true;
+    }
+    pmHDU *hduHigh = pmHDUGetHighest(fpa, chip, cell); // Highest HDU
+
+    if (cell && (cell->conceptsRead == PM_CONCEPT_SOURCE_NONE)) {
+        pmConceptsBlankCell(cell);
+        cell->conceptsRead = PM_CONCEPT_SOURCE_BLANK;
+    }
+    if (chip && (chip->conceptsRead == PM_CONCEPT_SOURCE_NONE)) {
+        pmConceptsBlankChip(chip);
+        chip->conceptsRead = PM_CONCEPT_SOURCE_BLANK;
+    }
+    if (fpa && (fpa->conceptsRead == PM_CONCEPT_SOURCE_NONE)) {
+        pmConceptsBlankFPA(fpa);
+        fpa->conceptsRead = PM_CONCEPT_SOURCE_BLANK;
+    }
+
+    bool success = true;                // Success in reading concepts?
+    if (source & PM_CONCEPT_SOURCE_CELLS && !(*read & PM_CONCEPT_SOURCE_CELLS) && cell) {
+        if (p_pmConceptsReadFromCells(target, *specs, cell)) {
+            *read |= PM_CONCEPT_SOURCE_CELLS;
+        } else {
+            psError(PS_ERR_UNKNOWN, false, "Error reading concepts from camera configuration.\n");
+            success = false;
+        }
+    }
+
+    if (source & PM_CONCEPT_SOURCE_DEFAULTS && !(*read & PM_CONCEPT_SOURCE_DEFAULTS)) {
+        if (p_pmConceptsReadFromDefaults(target, *specs, fpa, chip, cell)) {
+            *read |= PM_CONCEPT_SOURCE_DEFAULTS;
+        } else {
+            psError(PS_ERR_UNKNOWN, false, "Error reading concepts from defaults.\n");
+            success = false;
+        }
+    }
+
+    if (source & PM_CONCEPT_SOURCE_PHU && !(*read & PM_CONCEPT_SOURCE_PHU) && hduHigh->header) {
+        if (p_pmConceptsReadFromHeader(target, *specs, fpa, chip, cell)) {
+            *read |= PM_CONCEPT_SOURCE_PHU;
+        } else {
+            psError(PS_ERR_UNKNOWN, false, "Error reading concepts from PHU.\n");
+            success = false;
+        }
+    }
+
+    // If there are multiple HDUs, then it may be that one of them hasn't been read yet (hdu->header not set)
+    if (source & PM_CONCEPT_SOURCE_HEADER && !(*read & PM_CONCEPT_SOURCE_HEADER) &&
+        hduLow != hduHigh && hduLow->header) {
+        if (p_pmConceptsReadFromHeader(target, *specs, fpa, chip, cell)) {
+            *read |= PM_CONCEPT_SOURCE_HEADER;
+        } else {
+            psError(PS_ERR_UNKNOWN, false, "Error reading concepts from header.\n");
+            success = false;
+        }
+    }
+
+#ifdef HAVE_PSDB
+    if (source & PM_CONCEPT_SOURCE_DATABASE && !(*read & PM_CONCEPT_SOURCE_DATABASE)) {
+        if (p_pmConceptsReadFromDatabase(target, *specs, fpa, chip, cell, config)) {
+            *read |= PM_CONCEPT_SOURCE_DATABASE;
+        } else {
+            psError(PS_ERR_UNKNOWN, false, "Error reading concepts from database.\n");
+            success = false;
+        }
+    }
+#endif
+
+    pmConceptsUpdate(fpa, chip, cell);
+
+    return success;
+}
+
+
+
+
+bool pmConceptsRead(pmFPA *fpa, pmChip *chip, pmCell *cell, pmConceptSource source, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(fpa, false);
+    psMetadata *conceptsFPA = pmConceptsSpecs(PM_FPA_LEVEL_FPA); // Concept specifications
+    bool success = conceptsRead(&conceptsFPA, fpa, chip, cell, &fpa->conceptsRead, source,
+                                config, fpa->concepts);
+    if (chip) {
+        psMetadata *conceptsChip = pmConceptsSpecs(PM_FPA_LEVEL_CHIP); // Concept specifications
+        success &= conceptsRead(&conceptsChip, fpa, chip, cell, &chip->conceptsRead, source,
+                                config, chip->concepts);
+    }
+    if (cell) {
+        psMetadata *conceptsCell = pmConceptsSpecs(PM_FPA_LEVEL_CELL); // Concept specifications
+        success &= conceptsRead(&conceptsCell, fpa, chip, cell, &cell->conceptsRead, source,
+                                config, cell->concepts);
+    }
+
+    return success;
+}
+
+
+
+bool pmConceptsReadFPA(pmFPA *fpa, pmConceptSource source, bool propagateDown, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(fpa, false);
+    psMetadata *conceptsFPA = pmConceptsSpecs(PM_FPA_LEVEL_FPA); // Concept specifications
+    psTrace("psModules.concepts", 5, "Reading FPA concepts: %p %p\n", conceptsFPA, fpa->concepts);
+    bool success = conceptsRead(&conceptsFPA, fpa, NULL, NULL, &fpa->conceptsRead, source,
+                                config, fpa->concepts);
+    if (propagateDown) {
+        psArray *chips = fpa->chips;    // Array of chips
+        for (long i = 0; i < chips->n; i++) {
+            pmChip *chip = chips->data[i]; // Chip of interest
+            if (chip) {
+                success &= pmConceptsReadChip(chip, source, false, true, config);
+            }
+        }
+    }
+
+    return success;
+}
+
+
+
+bool pmConceptsReadChip(pmChip *chip, pmConceptSource source, bool propagateUp,
+                        bool propagateDown, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(chip, false);
+    psMetadata *conceptsChip = pmConceptsSpecs(PM_FPA_LEVEL_CHIP); // Concept specifications
+    psTrace("psModules.concepts", 5, "Reading chip concepts: %p %p\n", conceptsChip, chip->concepts);
+    pmFPA *fpa = chip->parent;          // FPA to which the chip belongs
+    bool success = conceptsRead(&conceptsChip, fpa, chip, NULL, &chip->conceptsRead, source, config,
+                                chip->concepts);
+    if (propagateUp) {
+        psMetadata *conceptsFPA = pmConceptsSpecs(PM_FPA_LEVEL_FPA); // Concept specifications
+        success &= conceptsRead(&conceptsFPA, fpa, chip, NULL, &fpa->conceptsRead, source,
+                                config, fpa->concepts);
+    }
+    if (propagateDown) {
+        psArray *cells = chip->cells;        // Array of cells
+        for (long i = 0; i < cells->n; i++) {
+            pmCell *cell = cells->data[i];  // Cell of interest
+            if (cell) {
+                success &= pmConceptsReadCell(cell, source, false, config);
+            }
+        }
+    }
+    return success;
+}
+
+
+bool pmConceptsReadCell(pmCell *cell, pmConceptSource source, bool propagateUp, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(cell, false);
+    psMetadata *conceptsCell = pmConceptsSpecs(PM_FPA_LEVEL_CELL); // Concept specifications
+    psTrace("psModules.concepts", 5, "Reading cell concepts: %p %p\n", conceptsCell, cell->concepts);
+    pmChip *chip = cell->parent;        // Chip to which the cell belongs
+    pmFPA *fpa = chip->parent;          // FPA to which the chip belongs
+
+    bool success = conceptsRead(&conceptsCell, fpa, chip, cell, &cell->conceptsRead, source, config,
+                                cell->concepts);
+    if (propagateUp) {
+        psMetadata *conceptsChip = pmConceptsSpecs(PM_FPA_LEVEL_CHIP); // Concept specifications
+        success &= conceptsRead(&conceptsChip, fpa, chip, cell, &chip->conceptsRead, source, config,
+                                chip->concepts);
+        psMetadata *conceptsFPA = pmConceptsSpecs(PM_FPA_LEVEL_FPA); // Concept specifications
+
+        success &= conceptsRead(&conceptsFPA, fpa, chip, cell, &fpa->conceptsRead, source, config,
+                                fpa->concepts);
+    }
+
+    return success;
+}
