Index: trunk/ppImage/src/Makefile.am
===================================================================
--- trunk/ppImage/src/Makefile.am	(revision 6624)
+++ trunk/ppImage/src/Makefile.am	(revision 6747)
@@ -2,13 +2,17 @@
 
 noinst_HEADERS = \
+	ppFile.h \
 	ppImage.h \
 	ppImageData.h \
 	ppImageDetrend.h \
-	ppImageOptions.h
+	ppImageOptions.h \
+	ppMem.h
 
 ppImage_CPPFLAGS = $(PSLIB_CFLAGS) $(PSMODULE_CFLAGS) $(ppImage_CFLAGS)
 ppImage_LDFLAGS = $(PSLIB_LIBS) $(PSMODULE_LIBS)
 ppImage_SOURCES = \
+	ppFile.c \
 	ppImage.c \
+	ppImageConfig.c \
 	ppImageData.c \
 	ppImageDetrendBias.c \
@@ -19,6 +23,6 @@
 	ppImageOptions.c \
 	ppImageParseCamera.c \
-	ppImageParseDetrend.c \
-	ppImageWeights.c
+	ppImageWeights.c \
+	ppMem.c
 #	ppImageLoadPixels.c
 #	ppDetrendFlat.c
@@ -30,5 +34,7 @@
 ppTest_CPPFLAGS = $(PSLIB_CFLAGS) $(PSMODULE_CFLAGS) $(ppImage_CFLAGS)
 ppTest_LDFLAGS = $(PSLIB_LIBS) $(PSMODULE_LIBS)
-ppTest_SOURCES = ppTest.c
+ppTest_SOURCES = \
+	ppTest.c \
+	ppMem.c
 
 
Index: trunk/ppImage/src/ppFile.c
===================================================================
--- trunk/ppImage/src/ppFile.c	(revision 6624)
+++ trunk/ppImage/src/ppFile.c	(revision 6747)
@@ -12,4 +12,5 @@
         psFitsClose(file->fits);
     }
+    psFree(file->view);
     return;
 }
@@ -25,4 +26,5 @@
     file->fits = NULL;
     file->phu = NULL;
+    file->view = NULL;
 
     return file;
@@ -30,2 +32,21 @@
 
 
+bool ppFileOpen(ppFile *file, const char *name, pmConfig *config, psMetadata *camera, psMetadata *format)
+{
+    file->fpa = pmFPAConstruct(camera);
+    psString filename = psMetadataLookupStr(NULL, config->arguments, name);
+    if (strlen(filename) == 0) {
+        return false;
+    }
+    file->filename = psMemIncrRefCounter(filename);
+    file->fits = psFitsOpen(filename, "r");
+    file->phu = psFitsReadHeader(NULL, file->fits);
+    if (!pmConfigValidateCameraFormat(format, file->phu)) {
+        psLogMsg(__func__, PS_LOG_WARN, "File %s doesn't match camera format --- ignored.\n", filename);
+        psFitsClose(file->fits);
+        return false;
+    }
+    file->view = pmFPAAddSource(file->fpa, file->phu, format);
+    return true;
+}
+
Index: trunk/ppImage/src/ppFile.h
===================================================================
--- trunk/ppImage/src/ppFile.h	(revision 6624)
+++ trunk/ppImage/src/ppFile.h	(revision 6747)
@@ -3,5 +3,5 @@
 
 #include "pslib.h"
-#include "pmFPA.h"
+#include "psmodules.h"
 
 // A file to process
@@ -11,10 +11,12 @@
     psMetadata *phu;                    // The FITS header
     pmFPA *fpa;                         // The FPA, with pixels and extensions
+    pmFPAview *view;                    // The view
 } ppFile;
 
 
-// Allocators
+// Allocator
 ppFile *ppFileAlloc(void);
 
+bool ppFileOpen(ppFile *file, const char *name, pmConfig *config, psMetadata *camera, psMetadata *format);
 
 #endif
Index: trunk/ppImage/src/ppImage.c
===================================================================
--- trunk/ppImage/src/ppImage.c	(revision 6624)
+++ trunk/ppImage/src/ppImage.c	(revision 6747)
@@ -1,5 +1,5 @@
 #include <stdio.h>
 #include "pslib.h"
-#include "pmConcepts.h"
+#include "psmodules.h"
 #include "ppImage.h"
 #include "ppMem.h"
@@ -11,10 +11,9 @@
     ppImageData *data = ppImageDataAlloc();
     ppImageOptions *options = ppImageOptionsAlloc();
-    ppConfig *config = ppConfigAlloc();
 
     psTimerStart(TIMERNAME);
 
     // Parse the configuration and arguments
-    ppImageConfig(config, argc, argv);
+    pmConfig *config = ppImageConfig(argc, argv);
 
     // Open the input image, output image, output mask
@@ -26,6 +25,10 @@
     ppImageOptionsParse(data, options, config);
 
+#if 0
+    // XXX I think we do this in ppImageParseCamera
+
     // open detrend images, load headers, optionally load pixels
     ppImageParseDetrend(data, options, config);
+#endif
 
     // Image Arithmetic Loop
Index: trunk/ppImage/src/ppImage.h
===================================================================
--- trunk/ppImage/src/ppImage.h	(revision 6624)
+++ trunk/ppImage/src/ppImage.h	(revision 6747)
@@ -3,42 +3,23 @@
 
 #include "pslib.h"
-#include "pmFPA.h"
-#include "ppConfig.h"
-#include "ppFile.h"
+#include "psmodules.h"
+
 #include "ppImageData.h"
 #include "ppImageOptions.h"
 
-
-#if 0
-#include <strings.h>
-#include "psAdditionals.h"
-#include "pmFPA.h"
-#include "pmFPAConstruct.h"
-#include "pmFPARead.h"
-#include "pmFPAWrite.h"
-#include "pmReadout.h"
-#include "pmConfig.h"
-#include "pmFlatField.h"
-#include "pmMaskBadPixels.h"
-#include "pmNonLinear.h"
-#include "pmChipMosaic.h"
-#include "pmSubtractBias.h"
-#endif
-
-
-#define RECIPE "PHASE2"                 // Name of the recipe to use
+#define RECIPE_NAME "PHASE2"            // Name of the recipe to use
 #define TIMERNAME "ppImage"             // Name of timer
 
 // Get the configuration
-bool ppImageConfig(ppConfig *config, int argc, char **argv);
+pmConfig *ppImageConfig(int argc, char **argv);
 
 // Determine what type of camera, and initialise
 bool ppImageParseCamera(ppImageData *data,   // The data to be processed
-                        ppConfig *config // Configuration
+                        pmConfig *config // Configuration
                         );
 
 
 // Loop over the input
-bool ppImageLoop(ppImageData *data, ppImageOptions *options, ppConfig *config);
+bool ppImageLoop(ppImageData *data, ppImageOptions *options, pmConfig *config);
 
 // Load the pixels for the given file
@@ -49,5 +30,5 @@
                        );
 
-bool ppImageParseDetrend(ppImageData *data, ppImageOptions *options, ppConfig *config);
+bool ppImageParseDetrend(ppImageData *data, ppImageOptions *options, pmConfig *config);
 
 bool ppReadoutWeights(pmReadout *readout);
@@ -56,7 +37,7 @@
 // These functions are not implemented, or not needed
 pmReadout* ppDetrendPedestal(pmReadout *pedestal, pmCell *input, pmReadout *bias, pmReadout *dark, float darkTime, ppImageOptions *options);
-bool ppImageOutput(ppImageData *data, ppConfig *config);
-bool ppImagePhot(ppImageData *data, ppImageOptions *options, ppConfig *config);
-bool ppFileOpen(ppFile *fpa, psMetadata *camera, char *name, bool doThis);
+bool ppImageOutput(ppImageData *data, pmConfig *config);
+bool ppImagePhot(ppImageData *data, ppImageOptions *options, pmConfig *config);
+bool ppFileOpen(ppFile *fpa, char *name, bool doThis);
 #endif
 
Index: trunk/ppImage/src/ppImageConfig.c
===================================================================
--- trunk/ppImage/src/ppImageConfig.c	(revision 6624)
+++ trunk/ppImage/src/ppImageConfig.c	(revision 6747)
@@ -1,14 +1,11 @@
 #include <stdio.h>
 #include "pslib.h"
-#include "pmConfig.h"
-#include "ppConfig.h"
+#include "psmodules.h"
 #include "ppImage.h"
 
-bool ppImageConfig(ppConfig *config, int argc, char **argv)
+pmConfig *ppImageConfig(int argc, char **argv)
 {
-    // XXX - this should be split into a function to parse argc,argv
-    //       and a second to read the config files.
-    //       all argc,argv should be interpretted before work is done.
-    if (! pmConfigRead(&config->site, &config->camera, &config->recipe, &argc, argv, RECIPE)) {
+    pmConfig *config = pmConfigRead(&argc, argv);
+    if (! config) {
         psErrorStackPrint(stderr, "Can't find site configuration!\n");
         exit(EXIT_FAILURE);
@@ -17,5 +14,4 @@
     // Parse other command-line arguments
     config->arguments = psMetadataAlloc(); // The arguments, with default values
-
     psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-key", 0, "exposure ID", "");
     psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-bias", 0, "Name of the bias image", "");
@@ -43,4 +39,4 @@
 #endif
 
-    return true;
+    return config;
 }
Index: trunk/ppImage/src/ppImageDetrend.h
===================================================================
--- trunk/ppImage/src/ppImageDetrend.h	(revision 6624)
+++ trunk/ppImage/src/ppImageDetrend.h	(revision 6747)
@@ -3,6 +3,5 @@
 
 #include "pslib.h"
-#include "pmFPA.h"
-#include "ppConfig.h"
+#include "psmodules.h"
 #include "ppImageOptions.h"
 
@@ -17,5 +16,5 @@
 
 
-bool ppImageDetrendCell(ppImageDetrend *detrend, ppImageOptions *options, ppConfig *config);
+bool ppImageDetrendCell(ppImageDetrend *detrend, ppImageOptions *options, pmConfig *config);
 bool ppImageDetrendMask(pmCell *cell, pmReadout *input, pmReadout *mask);
 bool ppImageDetrendNonLinear(pmCell *cell, pmReadout *input, ppImageOptions *options);
Index: trunk/ppImage/src/ppImageDetrendBias.c
===================================================================
--- trunk/ppImage/src/ppImageDetrendBias.c	(revision 6624)
+++ trunk/ppImage/src/ppImageDetrendBias.c	(revision 6747)
@@ -1,5 +1,5 @@
 #include <stdio.h>
 #include "pslib.h"
-#include "pmFPA.h"
+#include "psmodules.h"
 #include "ppImageOptions.h"
 #include "ppImageDetrend.h"
Index: trunk/ppImage/src/ppImageDetrendCell.c
===================================================================
--- trunk/ppImage/src/ppImageDetrendCell.c	(revision 6624)
+++ trunk/ppImage/src/ppImageDetrendCell.c	(revision 6747)
@@ -1,7 +1,7 @@
 #include <stdio.h>
 #include "pslib.h"
-#include "pmFPA.h"
-#include "pmFlatField.h"
+#include "psmodules.h"
 #include "ppImageDetrend.h"
+#include "ppImageOptions.h"
 
 // mask, bias, dark, flat are defined per Cell
@@ -22,7 +22,9 @@
 }
 
-bool ppImageDetrendCell(ppImageDetrend *detrend, ppImageOptions *options, ppConfig *config)
+bool ppImageDetrendCell(ppImageDetrend *detrend, ppImageOptions *options, pmConfig *config)
 {
+#if 0
     pmCellSetWeights(detrend->input);
+#endif
 
     pmReadout *mask = ppImageDetrendSelectFirst(detrend->mask, "mask", options->doMask);
Index: trunk/ppImage/src/ppImageDetrendFlat.c
===================================================================
--- trunk/ppImage/src/ppImageDetrendFlat.c	(revision 6624)
+++ trunk/ppImage/src/ppImageDetrendFlat.c	(revision 6747)
@@ -1,3 +1,6 @@
-# include "ppImage.h"
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppImage.h"
 
 // why does this use the flat pmReadout?
@@ -7,10 +10,10 @@
     psLogMsg("phase2", PS_LOG_INFO, "Performing flat field.\n");
 
-    
+
 
 #ifndef PRODUCTION
     psImage *dummyImage = psImageAlloc(inputReadout->image->numCols,
-				       inputReadout->image->numRows,
-				       PS_TYPE_U8);
+                                       inputReadout->image->numRows,
+                                       PS_TYPE_U8);
     pmReadout *dummyMask = pmReadoutAlloc(NULL);
     dummyMask->image = dummyImage;
Index: trunk/ppImage/src/ppImageDetrendMask.c
===================================================================
--- trunk/ppImage/src/ppImageDetrendMask.c	(revision 6624)
+++ trunk/ppImage/src/ppImageDetrendMask.c	(revision 6747)
@@ -1,5 +1,4 @@
 #include <stdio.h>
-#include "pmFPA.h"
-#include "pmMaskBadPixels.h"
+#include "psmodules.h"
 #include "ppImageDetrend.h"
 
Index: trunk/ppImage/src/ppImageDetrendNonLinear.c
===================================================================
--- trunk/ppImage/src/ppImageDetrendNonLinear.c	(revision 6624)
+++ trunk/ppImage/src/ppImageDetrendNonLinear.c	(revision 6747)
@@ -1,6 +1,5 @@
 #include <stdio.h>
 #include "pslib.h"
-#include "pmFPA.h"
-#include "pmNonLinear.h"
+#include "psmodules.h"
 #include "ppImageDetrend.h"
 
Index: trunk/ppImage/src/ppImageDetrendPedestal.c
===================================================================
--- trunk/ppImage/src/ppImageDetrendPedestal.c	(revision 6624)
+++ trunk/ppImage/src/ppImageDetrendPedestal.c	(revision 6747)
@@ -1,3 +1,6 @@
-# include "ppImage.h"
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppImage.h"
 
 // XXX check on image overlaps, as well as image sizes
@@ -13,52 +16,52 @@
 
     if (options->doDark) {
-	// Dark time for input image
-	float inputTime = psMetadataLookupF32(NULL, input->concepts, "CELL.DARKTIME");
-	if (inputTime <= 0) {
-	    psErrorStackPrint(stderr, "DARKTIME for input image (%f) is non-positive.\n",
-			      inputTime);
-	    exit(EXIT_FAILURE);
-	}
+        // Dark time for input image
+        float inputTime = psMetadataLookupF32(NULL, input->concepts, "CELL.DARKTIME");
+        if (inputTime <= 0) {
+            psErrorStackPrint(stderr, "DARKTIME for input image (%f) is non-positive.\n",
+                              inputTime);
+            exit(EXIT_FAILURE);
+        }
 
-	if (inputTime != lastExptime) {
-	    // this will create a new pedestal if the input one is NULL
-	    // XXX EAM : this function had darkTime * inputTime, which is wrong, yes?
-	    if (pedestal == NULL) {
-		pedestal = pmReadoutAlloc (NULL);
-	    }
-	    pedestal->col0    = dark->col0;
-	    pedestal->row0    = dark->row0;
-	    pedestal->colBins = dark->colBins;
-	    pedestal->rowBins = dark->rowBins;
+        if (inputTime != lastExptime) {
+            // this will create a new pedestal if the input one is NULL
+            // XXX EAM : this function had darkTime * inputTime, which is wrong, yes?
+            if (pedestal == NULL) {
+                pedestal = pmReadoutAlloc (NULL);
+            }
+            pedestal->col0    = dark->col0;
+            pedestal->row0    = dark->row0;
+            pedestal->colBins = dark->colBins;
+            pedestal->rowBins = dark->rowBins;
 
-	    pedestal->image   = (psImage *) psBinaryOp(pedestal->image, dark->image, "*", psScalarAlloc(inputTime / darkTime, PS_TYPE_F32));
-	    reusePedestal = false;
-	    lastExptime = inputTime
-	}
+            pedestal->image   = (psImage *) psBinaryOp(pedestal->image, dark->image, "*", psScalarAlloc(inputTime / darkTime, PS_TYPE_F32));
+            reusePedestal = false;
+            lastExptime = inputTime
+        }
     }
 
     // no bias image, return dark pedestal or NULL
     if (!options->doBias) {
-	return pedestal;
+        return pedestal;
     }
 
     // no dark image, return bias pedestal, or reuse
     if (!options->doDark) {
-	if (!pedestal) {
-	    pedestal = psMemIncrRefCounter(bias);
-	}
-	return pedestal;
+        if (!pedestal) {
+            pedestal = psMemIncrRefCounter(bias);
+        }
+        return pedestal;
     }
 
     if (reusePedestal) {
-	return pedestal;
+        return pedestal;
     }
 
     if (bias->image->numRows != dark->image->numRows ||
-	bias->image->numCols != dark->image->numCols) {
-	psError(PS_ERR_IO, true, "Bias and dark images have different dimensions: %dx%d vs %dx%d\n", 
-		bias->image->numCols, bias->image->numRows,
-		dark->image->numCols, dark->image->numRows);
-	exit(EXIT_FAILURE);
+        bias->image->numCols != dark->image->numCols) {
+        psError(PS_ERR_IO, true, "Bias and dark images have different dimensions: %dx%d vs %dx%d\n",
+                bias->image->numCols, bias->image->numRows,
+                dark->image->numCols, dark->image->numRows);
+        exit(EXIT_FAILURE);
     }
 
@@ -71,4 +74,4 @@
 
 // creates a new pedestal image for this readout
-// if the current exptime is the same as the last exptime, 
+// if the current exptime is the same as the last exptime,
 // reuses the supplied pedestal
Index: trunk/ppImage/src/ppImageLoadPixels.c
===================================================================
--- trunk/ppImage/src/ppImageLoadPixels.c	(revision 6624)
+++ trunk/ppImage/src/ppImageLoadPixels.c	(revision 6747)
@@ -1,4 +1,5 @@
-// XXX PAP: Need to look this over some more
-
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
 #include "ppImage.h"
 
Index: trunk/ppImage/src/ppImageLoop.c
===================================================================
--- trunk/ppImage/src/ppImageLoop.c	(revision 6624)
+++ trunk/ppImage/src/ppImageLoop.c	(revision 6747)
@@ -1,8 +1,5 @@
 #include <stdio.h>
 #include "pslib.h"
-#include "pmFPA.h"
-#include "pmFPARead.h"
-#include "pmChipMosaic.h"
-#include "pmFPAWrite.h"
+#include "psmodules.h"
 #include "ppImageDetrend.h"
 #include "ppImage.h"
@@ -13,12 +10,9 @@
 // Read the entire FPA
 void readFPA(ppFile *file,              // File to read
-             ppConfig *config           // Configuration, containing the DB handle
+             pmConfig *config           // Configuration, containing the DB handle
     )
 {
     if (file->fpa && file->fits) {
-        if (! pmFPARead(file->fpa, file->fits, file->phu, config->database)) {
-            psErrorStackPrint(stderr, "Unable to populate camera from input FITS file\n");
-            exit(EXIT_FAILURE);
-        }
+        pmFPARead(file->fpa, file->fits, config->database);
     }
 }
@@ -26,22 +20,30 @@
 // Read a specified chip only
 void readChip(ppFile *file,             // File to read
-              ppConfig *config,         // Configuration
+              pmConfig *config,         // Configuration
               int chipNum               // Chip number to read
     )
 {
-    pmFPASelectChip(file->fpa, chipNum);
-    readFPA(file, config);
+    pmFPA *fpa = file->fpa;             // The FPA
+    if (fpa && file->fits) {
+        pmChip *chip = fpa->chips->data[chipNum]; // The chip
+        pmChipRead(chip, file->fits, config->database);
+    }
 }
 
 
-void readCell(ppFile *file, ppConfig *config, int chipNum, int cellNum)
+void readCell(ppFile *file, pmConfig *config, int chipNum, int cellNum)
 {
-    pmChip *chip = file->fpa->chips->data[chipNum];
-    pmChipSelectCell(chip, cellNum);
-    readFPA(file, config);
+    pmFPA *fpa = file->fpa;             // The FPA
+    if (fpa && file->fits) {
+        pmChip *chip = fpa->chips->data[chipNum]; // The chip
+        if (chip) {
+            pmCell *cell = chip->cells->data[cellNum]; // The cell
+            pmCellRead(cell, file->fits, config->database);
+        }
+    }
 }
 
 
-bool ppImageLoop(ppImageData *data, ppImageOptions *options, ppConfig *config)
+bool ppImageLoop(ppImageData *data, ppImageOptions *options, pmConfig *config)
 {
     ppImageDetrend detrend;
@@ -108,8 +110,7 @@
         }
 
+#if 0
         int numMosaicked = pmChipMosaic(inputChip, 1, 1); // Number of cells mosaicked together
         psLogMsg(__func__, PS_LOG_INFO, "%d cells mosaicked.\n", numMosaicked);
-
-        // XXX EAM: Photometry goes here!
 
         // XXX A kludge to get the write to behave w.r.t. the concepts --- we've changed the camera format, so
@@ -117,6 +118,13 @@
         const psMetadata *camera = data->input->fpa->camera;
         data->input->fpa->camera = NULL;
-        pmFPAWrite(data->output, data->input->fpa, config->database);
+#endif
+
+        // XXX Photometry goes here!
+
+        pmChipWrite(inputChip, data->output, config->database);
+
+#if 0
         data->input->fpa->camera = camera;
+#endif
 
         // Now I can blow away the mosaic so I can then read more.
Index: trunk/ppImage/src/ppImageOptions.c
===================================================================
--- trunk/ppImage/src/ppImageOptions.c	(revision 6624)
+++ trunk/ppImage/src/ppImageOptions.c	(revision 6747)
@@ -1,5 +1,5 @@
 #include <stdio.h>
 #include "pslib.h"
-#include "ppConfig.h"
+#include "ppImage.h"
 #include "ppImageData.h"
 #include "ppImageOptions.h"
@@ -28,5 +28,5 @@
 // XXX EAM : this needs signficant work to choose the detrend images based on the detrend database
 
-bool ppImageOptionsParse(ppImageData *data, ppImageOptions *options, ppConfig *config)
+bool ppImageOptionsParse(ppImageData *data, ppImageOptions *options, pmConfig *config)
 {
 
@@ -56,5 +56,11 @@
 
     bool mdStatus = false;              // Result of MD lookup
-    const char *depth = psMetadataLookupStr(&mdStatus, config->recipe, "LOAD.DEPTH");
+    psMetadata *recipe = psMetadataLookupMD(&mdStatus, config->recipes, RECIPE_NAME);
+    if (! mdStatus || !recipe) {
+        psLogMsg("ppImage", PS_LOG_ERROR, "Can't find recipe %s in the RECIPES.\n", RECIPE_NAME);
+        exit(EXIT_FAILURE);
+    }
+
+    const char *depth = psMetadataLookupStr(&mdStatus, recipe, "LOAD.DEPTH");
     if (! mdStatus || ! depth || strlen(depth) == 0) {
         psLogMsg("ppImage", PS_LOG_ERROR, "LOAD.DEPTH not specified in recipe.");
@@ -68,10 +74,10 @@
         options->imageLoadDepth = PP_LOAD_CELL;
     } else {
-        psLogMsg(__func__, PS_LOG_ERROR, "LOAD.DEPTH in recipe is not FPA, CHIP or CELL.");
+        psLogMsg(__func__, PS_LOG_ERROR, "LOAD.DEPTH in recipe %s is not FPA, CHIP or CELL.", RECIPE_NAME);
         exit(EXIT_FAILURE);
     }
 
     // Mask recipe options
-    if (psMetadataLookupBool(NULL, config->recipe, "MASK")) {
+    if (psMetadataLookupBool(NULL, recipe, "MASK")) {
         data->mask->filename = psMetadataLookupStr(NULL, config->arguments, "-mask");
         if (data->mask->filename && strlen(data->mask->filename) > 0) {
@@ -84,9 +90,9 @@
 
     // Non-linearity recipe options
-    if (psMetadataLookupBool(NULL, config->recipe, "NONLIN")) {
-        psMetadataItem *dataItem = psMetadataLookup(config->recipe, "NONLIN.DATA");
+    if (psMetadataLookupBool(NULL, recipe, "NONLIN")) {
+        psMetadataItem *dataItem = psMetadataLookup(recipe, "NONLIN.DATA");
         if (! dataItem) {
             psLogMsg(__func__, PS_LOG_ERROR, "Non-linearity correction desired, but unable to "
-                     "find NONLIN.DATA in recipe.");
+                     "find NONLIN.DATA in recipe %s.", RECIPE_NAME);
             exit(EXIT_FAILURE);
         }
@@ -106,8 +112,8 @@
             {
                 bool status;
-                options->nonLinearSource = psMetadataLookupStr(&status, config->recipe, "NONLIN.SOURCE");
+                options->nonLinearSource = psMetadataLookupStr(&status, recipe, "NONLIN.SOURCE");
                 if (! status || ! options->nonLinearSource) {
                     psLogMsg(__func__, PS_LOG_ERROR, "Non-linearity correction desired, but unable to "
-                            "find NONLIN.SOURCE in recipe");
+                            "find NONLIN.SOURCE in recipe %s.", RECIPE_NAME);
                     exit(EXIT_FAILURE);
                 }
@@ -116,5 +122,5 @@
           default:
             psLogMsg(__func__, PS_LOG_ERROR, "Non-linearity correction desired, but "
-                    "NONLIN.DATA is of invalid type.");
+                    "NONLIN.DATA is of invalid type in recipe %s.", RECIPE_NAME);
             exit(EXIT_FAILURE);
         }
@@ -122,22 +128,22 @@
 
     // Bias recipe options
-    if (psMetadataLookupBool(NULL, config->recipe, "BIAS")) {
+    if (psMetadataLookupBool(NULL, recipe, "BIAS")) {
         data->bias->filename = psMetadataLookupStr(NULL, config->arguments, "-bias");
         if (data->bias->filename && strlen(data->bias->filename) > 0) {
             options->doBias = true;
         } else {
-            psLogMsg(__func__, PS_LOG_WARN, "Bias subtraction is desired, but no bias was supplied --- "
-                     "no bias subtraction will be performed.\n");
+            psLogMsg(__func__, PS_LOG_WARN, "Bias subtraction is desired in recipe %s, but no bias was "
+                     "supplied --- no bias subtraction will be performed.\n", RECIPE_NAME);
         }
     }
 
     // Dark recipe options
-    if (psMetadataLookupBool(NULL, config->recipe, "DARK")) {
+    if (psMetadataLookupBool(NULL, recipe, "DARK")) {
         data->dark->filename = psMetadataLookupStr(NULL, config->arguments, "-dark");
         if (data->dark->filename && strlen(data->dark->filename) > 0) {
             options->doDark = true;
         } else {
-            psLogMsg(__func__, PS_LOG_WARN, "Dark subtraction is desired, but no dark was supplied --- "
-                     "no dark subtraction will be performed.\n");
+            psLogMsg(__func__, PS_LOG_WARN, "Dark subtraction is desired in recipe %s, but no dark was "
+                     "supplied --- no dark subtraction will be performed.\n", RECIPE_NAME);
         }
     }
@@ -147,26 +153,26 @@
     // Overscan recipe options
     // XXX EAM : we should abort on invalid options. default options?
-    if (psMetadataLookupBool(NULL, config->recipe, "OVERSCAN")) {
+    if (psMetadataLookupBool(NULL, recipe, "OVERSCAN")) {
         options->doOverscan = true;
 
         // Do the overscan as a single value?
-        overscanSingle = psMetadataLookupBool(NULL, config->recipe, "OVERSCAN.SINGLE");
+        overscanSingle = psMetadataLookupBool(NULL, recipe, "OVERSCAN.SINGLE");
 
         // How do we fit it?
-        psString fit = psMetadataLookupStr(NULL, config->recipe, "OVERSCAN.FIT");
+        psString fit = psMetadataLookupStr(NULL, recipe, "OVERSCAN.FIT");
         if (! strcasecmp(fit, "POLYNOMIAL")) {
             overscanFit = PM_FIT_POLY_ORD;
-            overscanOrder = psMetadataLookupS32(NULL, config->recipe, "OVERSCAN.ORDER");
+            overscanOrder = psMetadataLookupS32(NULL, recipe, "OVERSCAN.ORDER");
         } else if (! strcasecmp(fit, "CHEBYSHEV")) {
             overscanFit = PM_FIT_POLY_CHEBY;
-            overscanOrder = psMetadataLookupS32(NULL, config->recipe, "OVERSCAN.ORDER");
+            overscanOrder = psMetadataLookupS32(NULL, recipe, "OVERSCAN.ORDER");
         } else if (! strcasecmp(fit, "SPLINE")) {
             overscanFit = PM_FIT_SPLINE;
         } else if (strcasecmp(fit, "NONE")) {
-            psLogMsg(__func__, PS_LOG_WARN, "OVERSCAN.FIT (%s) is not one of NONE, POLYNOMIAL, or SPLINE:"
-                     " assuming NONE.\n", fit);
-        }
-
-        psString stat = psMetadataLookupStr(NULL, config->recipe, "OVERSCAN.STAT");
+            psLogMsg(__func__, PS_LOG_WARN, "OVERSCAN.FIT (%s) in recipe %s is not one of NONE, "
+                     "POLYNOMIAL, or SPLINE: assuming NONE.\n", fit, RECIPE_NAME);
+        }
+
+        psString stat = psMetadataLookupStr(NULL, recipe, "OVERSCAN.STAT");
         if (! strcasecmp(stat, "MEAN")) {
             overscanStats = psStatsAlloc(PS_STAT_SAMPLE_MEAN);
@@ -174,5 +180,6 @@
             overscanStats = psStatsAlloc(PS_STAT_SAMPLE_MEDIAN);
         } else {
-            psErrorStackPrint(stderr, "OVERSCAN.STAT (%s) is not one of MEAN, MEDIAN: assuming MEAN\n", stat);
+            psErrorStackPrint(stderr, "OVERSCAN.STAT (%s) in recipe %s is not one of MEAN, MEDIAN: "
+                              "assuming MEAN\n", stat, RECIPE_NAME);
             overscanStats = psStatsAlloc(PS_STAT_SAMPLE_MEAN);
         }
@@ -184,11 +191,11 @@
 
     // flat-field - recipe options
-    if (psMetadataLookupBool(NULL, config->recipe, "FLAT")) {
+    if (psMetadataLookupBool(NULL, recipe, "FLAT")) {
         data->flat->filename = psMetadataLookupStr(NULL, config->arguments, "-flat");
         if (strlen(data->flat->filename) > 0) {
             options->doFlat = true;
         } else {
-            psLogMsg(__func__, PS_LOG_WARN, "Flat-fielding is desired, but no flat was supplied --- "
-                     "no flat-fielding will be performed.\n");
+            psLogMsg(__func__, PS_LOG_WARN, "Flat-fielding is desired in recipe %s, but no flat was "
+                     "supplied --- no flat-fielding will be performed.\n", RECIPE_NAME);
         }
     }
Index: trunk/ppImage/src/ppImageOptions.h
===================================================================
--- trunk/ppImage/src/ppImageOptions.h	(revision 6624)
+++ trunk/ppImage/src/ppImageOptions.h	(revision 6747)
@@ -3,5 +3,5 @@
 
 #include "pslib.h"
-#include "pmSubtractBias.h"
+#include "psmodules.h"
 #include "ppImageData.h"
 #include "ppConfig.h"
@@ -38,5 +38,5 @@
 bool ppImageOptionsParse(ppImageData *data, // The data to be processed
                          ppImageOptions *options, // Processing options
-                         ppConfig *config    // Configuration
+                         pmConfig *config    // Configuration
     );
 
Index: trunk/ppImage/src/ppImageOutput.c
===================================================================
--- trunk/ppImage/src/ppImageOutput.c	(revision 6624)
+++ trunk/ppImage/src/ppImageOutput.c	(revision 6747)
@@ -1,5 +1,8 @@
-# include "ppImage.h"
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
+#include "ppImage.h"
 
-bool ppImageOutput(ppData *data, ppConfig *config)
+bool ppImageOutput(ppData *data, pmConfig *config)
 {
     const char *outname = psMetadataLookupStr(NULL, config->arguments, "-output"); // Name of output file
Index: trunk/ppImage/src/ppImageParseCamera.c
===================================================================
--- trunk/ppImage/src/ppImageParseCamera.c	(revision 6624)
+++ trunk/ppImage/src/ppImageParseCamera.c	(revision 6747)
@@ -1,10 +1,8 @@
 #include <stdio.h>
 #include "pslib.h"
-#include "pmFPA.h"
-#include "pmFPAConstruct.h"
-#include "pmConfig.h"
+#include "psmodules.h"
 #include "ppImage.h"
 
-bool ppImageParseCamera(ppImageData *data, ppConfig *config)
+bool ppImageParseCamera(ppImageData *data, pmConfig *config)
 {
     // Initialise the containers where the files will go
@@ -22,5 +20,5 @@
     data->input->fits = psFitsOpen(data->input->filename, "r"); // File handle for FITS file
     if (! data->input->fits) {
-        // There's no point in continuing if we can't open the input
+        // We can't open the input
         psErrorStackPrint(stderr, "Can't open input image: %s\n", data->input->filename);
         exit(EXIT_FAILURE);
@@ -29,6 +27,7 @@
 
     // Get camera configuration from header if not already defined
+    psMetadata *cameraFormat = NULL;    // Camera format description
     if (! config->camera) {
-        config->camera = pmConfigCameraFromHeader(config->site, data->input->phu);
+        cameraFormat = pmConfigCameraFormatFromHeader(config, data->input->phu);
         if (! config->camera) {
              // There's no point in continuing if we can't recognise what we've got
@@ -36,6 +35,6 @@
             exit(EXIT_FAILURE);
         }
-   } else if (! pmConfigValidateCamera(config->camera, data->input->phu)) {
-       // There's no point in continuing if what we've got doesn't match what we've been told
+    } else if (! pmConfigValidateCameraFormat(config->camera, data->input->phu)) {
+        // What we've got doesn't match what we've been told
         psError(PS_ERR_IO, true, "%s does not seem to be from the specified camera.\n",
                 data->input->filename);
@@ -43,18 +42,15 @@
     }
 
-    // Determine the correct recipe to use
-    if (! config->recipe && !(config->recipe = pmConfigRecipeFromCamera(config->camera, RECIPE))) {
-        // There's no point in continuing if we can't work out what recipe to use
-        psErrorStackPrint(stderr, "Can't find recipe configuration!\n");
-        exit(EXIT_FAILURE);
-    }
+    // Construct cameras in preparation for reading
+    data->input->fpa  = pmFPAConstruct(config->camera);
+    data->input->view = pmFPAAddSource(data->input->fpa, data->input->phu, cameraFormat);
 
-    // Construct cameras in preparation for reading
-    data->input->fpa   = pmFPAConstruct(config->camera);
-    data->mask->fpa    = pmFPAConstruct(config->camera);
-    data->bias->fpa    = pmFPAConstruct(config->camera);
-    data->dark->fpa    = pmFPAConstruct(config->camera);
-    data->flat->fpa    = pmFPAConstruct(config->camera);
-    data->fringe->fpa  = pmFPAConstruct(config->camera);
+    ppFileOpen(data->mask, "-mask", config, config->camera, cameraFormat);
+    ppFileOpen(data->bias, "-bias", config, config->camera, cameraFormat);
+    ppFileOpen(data->dark, "-dark", config, config->camera, cameraFormat);
+    ppFileOpen(data->flat, "-flat", config, config->camera, cameraFormat);
+    ppFileOpen(data->fringe, "-fringe", config, config->camera, cameraFormat);
+
+    psFree(cameraFormat);
 
     // Open output file
@@ -66,19 +62,5 @@
     }
 
-    // XXX EAM : extend this to allow an array of selected chips by name
-    // Chip selection: if we are using a single chip, select it for each FPA
-    int chipNum = psMetadataLookupS32(NULL, config->arguments, "-chip"); // Chip number to work on
-    if (chipNum >= 0) {
-        if (! pmFPASelectChip(data->input->fpa, chipNum)) {
-            psErrorStackPrint(stderr, "Chip number %d doesn't exist in camera.\n", chipNum);
-            exit(EXIT_FAILURE);
-        }
-        psLogMsg("ppImage", PS_LOG_INFO, "Operating only on chip %d\n", chipNum);
-    }
     return true;
 }
 
-// XXX EAM : I dropped the pre-open of the output files; replace with a stats test of output permissions
-
-// XXX : for split data (data spread across multiple files), this step is only operating on a component
-//       of the FPA.  the other components should be set to 'invalid' in this case?
Index: trunk/ppImage/src/ppImageParseDetrend.c
===================================================================
--- trunk/ppImage/src/ppImageParseDetrend.c	(revision 6624)
+++ trunk/ppImage/src/ppImageParseDetrend.c	(revision 6747)
@@ -1,5 +1,5 @@
 #include <stdio.h>
 #include "pslib.h"
-#include "pmConfig.h"
+#include "psmodules.h"
 #include "ppFile.h"
 #include "ppImageData.h"
@@ -14,27 +14,10 @@
 // XXX : add fringe frame
 
-bool ppFileOpen(ppFile *file, psMetadata *camera, char *name, bool doThis) {
-
-    if (!doThis) {
-        return false;
-    }
-
-    psLogMsg("phase2", PS_LOG_INFO, "Opening %s image: %s\n", name, file->filename);
-    file->fits = psFitsOpen(file->filename, "r"); // File handle
-    file->phu = psFitsReadHeader(NULL, file->fits); // primary header
-    if (! pmConfigValidateCamera(camera, file->phu)) {
-        psError(PS_ERR_IO, true, "%s (%s) does not seem to be from the correct camera.\n", name,
-                file->filename);
-        exit(EXIT_FAILURE);
-    }
+bool ppImageParseDetrend(ppImageData *data, ppImageOptions *options, pmConfig *config)
+{
+    ppFileOpen(data->mask, "mask", options->doMask);
+    ppFileOpen(data->bias, "bias", options->doBias);
+    ppFileOpen(data->dark, "dark", options->doDark);
+    ppFileOpen(data->flat, "flat", options->doFlat);
     return true;
 }
-
-bool ppImageParseDetrend(ppImageData *data, ppImageOptions *options, ppConfig *config) {
-
-    ppFileOpen(data->mask, config->camera, "mask", options->doMask);
-    ppFileOpen(data->bias, config->camera, "bias", options->doBias);
-    ppFileOpen(data->dark, config->camera, "dark", options->doDark);
-    ppFileOpen(data->flat, config->camera, "flat", options->doFlat);
-    return true;
-}
Index: trunk/ppImage/src/ppImagePhot.c
===================================================================
--- trunk/ppImage/src/ppImagePhot.c	(revision 6624)
+++ trunk/ppImage/src/ppImagePhot.c	(revision 6747)
@@ -1,5 +1,8 @@
+#include <stdio.h>
+#include "pslib.h"
+#include "psmodules.h"
 #include "ppImage.h"
 
-bool ppImagePhot(ppData *data, ppOptions *options, ppConfig *config)
+bool ppImagePhot(ppData *data, ppOptions *options, pmConfig *config)
 {
     ppFile *input = data->input;        // The input file information
Index: trunk/ppImage/src/ppImageWeights.c
===================================================================
--- trunk/ppImage/src/ppImageWeights.c	(revision 6624)
+++ trunk/ppImage/src/ppImageWeights.c	(revision 6747)
@@ -1,5 +1,5 @@
 #include <stdio.h>
 #include "pslib.h"
-#include "pmFPA.h"
+#include "psmodules.h"
 #include "ppImage.h"
 
Index: trunk/ppImage/src/ppTest.c
===================================================================
--- trunk/ppImage/src/ppTest.c	(revision 6624)
+++ trunk/ppImage/src/ppTest.c	(revision 6747)
@@ -3,4 +3,5 @@
 #include "pslib.h"
 #include "psmodules.h"
+#include "ppMem.h"
 
 int main(int argc, char *argv[])
@@ -96,23 +97,30 @@
     // Read the FPA
     pmFPARead(fpa, inFile, NULL);
+    // Copy to new camera format
+    pmFPA *newFPA = pmFPAConstruct(config->camera);
+    psMetadata *newFormat = psMetadataConfigParse(NULL, NULL, "mcshort_splice.config", true);
+    pmConfigConformHeader(phu, newFormat);
+    pmFPAview *newView = pmFPAAddSource(newFPA, phu, newFormat);
+    printf("View chip: %d\n", newView->chip);
+    printf("View cell: %d\n", newView->cell);
+    pmFPACopy(newFPA, fpa);
+    pmFPAWrite(newFPA, outFile, NULL);
+    pmFPAPrint(newFPA, false, true);
 
-    // How'd we do?
-    pmFPAPrint(fpa, true);
-#if 1
-    pmChip *chip = fpa->chips->data[13];
-    psString chipName = psMetadataLookupStr(NULL, chip->concepts, "CHIP.NAME");
-    printf("CELL.NAME for chip 13: %s\n", chipName);
-    pmCell *cell = chip->cells->data[0];
-    psMetadataPrint(cell->concepts, 10);
-#endif
-
-
-    pmFPAWrite(fpa, outFile, NULL);
-
+    psFree(newView);
+    psFree(newFormat);
+    psFree(newFPA);
+    psFree(view);
+    psFree(fpa);
+    psFree(config);
     psFitsClose(inFile);
     psFitsClose(outFile);
     psFree(phu);
     psFree(cameraFormat);
-    psFree(fpa);
+
+    psTimerStop();
+    psTraceReset();
+    pmConceptsDone();
+    ppMemCheck();
 
     // Pau.
