Index: trunk/psModules/src/config/pmConfig.c
===================================================================
--- trunk/psModules/src/config/pmConfig.c	(revision 17990)
+++ trunk/psModules/src/config/pmConfig.c	(revision 17991)
@@ -77,4 +77,43 @@
     return;
 }
+
+int checkEndForWord (const char *line, const char *word) {
+
+    int wlen = strlen (word);
+    int nlen = strlen (line);
+
+    if (nlen < wlen) return 0;
+
+    char *ptr = (char *) line + nlen - wlen;
+
+    if (strcasecmp (ptr, word)) return 0;
+
+    return (nlen - wlen);
+}
+
+// the camera name is of the form: BASE, BASE_CHIP, or BASE_FPA.  pull out BASE:
+char *cameraBaseName (const char *name) {
+
+    int N;
+    char *answer;
+
+    N = checkEndForWord (name, "-CHIP");
+    if (N && name[0] == '_') {
+	answer = psStringNCopy (name + 1, N - 1); 
+	psStringPrepend (&answer, "_");
+	return answer;
+    }
+    
+    N = checkEndForWord (name, "-FPA");
+    if (N && name[0] == '_') {
+	answer = psStringNCopy (name + 1, N - 1); 
+	psStringPrepend (&answer, "_");
+	return answer;
+    }
+    
+    answer = psStringCopy (name); 
+    return answer;
+}
+
 
 pmConfig *pmConfigAlloc()
@@ -973,5 +1012,7 @@
 
 // Given a camera and a header, see if any of the camera formats match the header
-static bool formatFromHeader(psMetadata **format, // Format to return
+// if so, return the winning format and the name of the winning format (both allocated here)
+static bool formatFromHeader(bool *status,
+			     psMetadata **format, // Format to return
                              psString *name, // Name to return
                              psMetadata *camera, // Camera configuration
@@ -986,4 +1027,5 @@
     assert(*cameraName);
 
+    *status = true; 			// error status
     bool result = false;                // Did we find the first match?
 
@@ -993,4 +1035,5 @@
     if (!mdok || !formats) {
         psError(PS_ERR_UNKNOWN, false, "Unable to find list of FORMATS in camera %s", cameraName);
+	*status = false;
         return false;
     }
@@ -998,4 +1041,5 @@
     if (!metadataReadFiles(formats, "camera format")) {
         psError(PS_ERR_UNKNOWN, false, "Unable to read cameras formats within camera configuration.\n");
+	*status = false;
         return false;
     }
@@ -1014,4 +1058,5 @@
             psError (PS_ERR_UNKNOWN, false, "Error in config scripts for camera %s, format %s\n",
                      cameraName, formatsItem->name);
+	    *status = false;
             return false;
         }
@@ -1030,14 +1075,18 @@
     }
     psFree(formatsIter);
+    *status = true;
     return result;
 }
 
-// we only need to read the recipe for the main camera images.  for additional images (eg, sky
-// cells) do not need to re-read the recipe files!
-psMetadata *pmConfigCameraFormatFromHeader(pmConfig *config, const psMetadata *header, bool readRecipes)
+// determine the camera format based on the keywords in the header.  If we have already chosen
+// a camera, then we select the formats only from that camera, and the meta-cameras for that
+// camera.  If we are discovering the camera (config->camera == NULL), then we also load the
+// recipe files for the camera.
+psMetadata *pmConfigCameraFormatFromHeader(psMetadata **camera, psString *formatName, pmConfig *config, const psMetadata *header, bool readRecipes)
 {
     PS_ASSERT_PTR_NON_NULL(config, NULL);
     PS_ASSERT_PTR_NON_NULL(header, NULL);
 
+    bool status = false;		// error status
     psMetadata *format = NULL;          // The winning format
     psString name = NULL;               // Name of the winning format
@@ -1045,4 +1094,8 @@
     // If we don't know what sort of camera we have, we try all that we know
     if (! config->camera) {
+	psAssert (!config->cameraName, "programming error: cameraName should be NULL if camera is undefined");
+	psAssert (!config->format,     "programming error: format should be NULL if camera is undefined");
+	psAssert (!config->formatName, "programming error: formatName should be NULL if camera is undefined");
+
         bool mdok;                      // Metadata lookup status
         psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->complete, "CAMERAS");
@@ -1066,30 +1119,26 @@
             assert(camerasItem->type == PS_DATA_METADATA); // It should be because we've read it in or deleted
             psMetadata *testCamera = camerasItem->data.md; // Camera to test against what we've got:
-            if (formatFromHeader(&format, &name, testCamera, header, camerasItem->name)) {
-                // Set the defaults, if they are not already set
-                if (!config->camera && !config->cameraName) {
-                    config->camera = psMemIncrRefCounter(testCamera);
-                    config->cameraName = psStringCopy(camerasItem->name);
-                }
-                if (!config->format && !config->formatName) {
-                    config->formatName = name;
-                    config->format = format;
-                } else {
-                    psFree(name);
-                    psFree(format);
-                }
-            } else {
-              // XXX have to be careful with this construction: it catches other errors cluttering up the stack...
-                psErr *error = psErrorLast();
-                if (error->code != PS_ERR_NONE) {
+            if (formatFromHeader(&status, &format, &name, testCamera, header, camerasItem->name)) {
+		config->camera = psMemIncrRefCounter(testCamera);
+		config->cameraName = psStringCopy(camerasItem->name);
+		config->formatName = name;
+		config->format = format;
+		if (camera) {
+		    *camera = psMemIncrRefCounter(testCamera);	// view on value saved on config
+		} 
+		if (formatName) {
+		    *formatName = psMemIncrRefCounter(name);	// view on value saved on config
+		}
+	    } else {
+		if (!status) {
                     psError(PS_ERR_IO, false, "Error reading camera config data for %s", camerasItem->name);
                     return NULL;
                 }
-                psFree(error);
-            }
-        } // Done looking at all cameras
+            }
+        } 
         psFree(camerasIter);
 
-        if (! config->camera) {
+	// Done looking at all cameras
+        if (!config->camera) {
             psError(PS_ERR_IO, false, "Unable to find a camera that matches input FITS header!");
             return NULL;
@@ -1104,24 +1153,76 @@
     }
 
-    // Otherwise, try the specific camera
-    if (!formatFromHeader(&format, &name, config->camera, header, config->cameraName)) {
+    // we have a config with a specified camera.  However, the supplied header may not
+    // correspond to this mosaic level for the camera.  We need to try the CHIP and FPA mosaic
+    // versions as well as the base version
+
+    psAssert (config->cameraName, "programming error: cameraName should not be NULL if camera is defined");
+    psAssert (config->format,     "programming error: format should not be NULL if camera is defined");
+    psAssert (config->formatName, "programming error: formatName should not be NULL if camera is defined");
+
+    // the camera name is of the form: BASE, BASE_CHIP, or BASE_FPA.  pull out BASE:
+    char *baseName = cameraBaseName (config->cameraName);
+
+    bool found = false;
+
+    psMetadata *testCamera = NULL;
+    char *testName = NULL;
+
+    psMetadata *cameras = psMetadataLookupMetadata (NULL, config->complete, "CAMERAS");
+    psAssert (cameras, "missing CAMERAS in complete metadata");
+
+    // try the FPA metaCamera
+    if (!found) {
+	testName = NULL;
+	psStringAppend (&testName, "_%s-FPA", baseName);
+
+	testCamera = psMetadataLookupMetadata (NULL, cameras, testName);
+	psAssert (testCamera, "missing %s in CAMERAS in complete metadata", testName);
+    
+	bool status;
+	found = formatFromHeader(&status, &format, &name, testCamera, header, testName);
+	if (!found) psFree (testName);
+    }
+
+    // try the CHIP metaCamera
+    if (!found) {
+	testName = NULL;
+	psStringAppend (&testName, "_%s-CHIP", baseName);
+
+	testCamera = psMetadataLookupMetadata (NULL, cameras, testName);
+	psAssert (testCamera, "missing %s in CAMERAS in complete metadata", testName);
+    
+	bool status;
+	found = formatFromHeader(&status, &format, &name, testCamera, header, testName);
+	if (!found) psFree (testName);
+    }
+
+    // try the base name
+    if (!found) {
+	testName = psMemIncrRefCounter (baseName);
+
+	testCamera = psMetadataLookupMetadata (NULL, cameras, testName);
+	psAssert (testCamera, "missing %s in CAMERAS in complete metadata", testName);
+    
+	bool status;
+	found = formatFromHeader(&status, &format, &name, testCamera, header, testName);
+    }
+
+    if (!found) {
         psError(PS_ERR_IO, true, "Unable to find a format with the specified camera (%s) that matches the "
-                "given header.\n", config->cameraName);
+                "given header.\n", baseName);
+	psFree (baseName);
         return NULL;
     }
-
-    // Now that we have the camera, we can apply recipes based on command-line arguments
-    if (readRecipes && !pmConfigReadRecipes(config, PM_RECIPE_SOURCE_CL)) {
-        psError(PS_ERR_IO, false, "Error reading recipes from camera config for %s", config->cameraName);
-        return NULL;
-    }
-
-    if (!config->format && !config->formatName) {
-        config->formatName = name;
-        config->format = format;
+    
+    psFree (baseName);
+    if (formatName) {
+	*formatName = testName;
     } else {
-        psFree(format);
-        psFree(name);
-    }
+	psFree (testName);
+    }
+    if (camera) {
+	*camera = psMemIncrRefCounter(testCamera);
+    } 
     return psMemIncrRefCounter(format);
 }
