Index: trunk/psModules/src/config/pmConfigCamera.c
===================================================================
--- trunk/psModules/src/config/pmConfigCamera.c	(revision 17993)
+++ trunk/psModules/src/config/pmConfigCamera.c	(revision 18939)
@@ -23,23 +23,76 @@
 static void removeChipConceptsSources(psMetadata *source);
 
-// Generate the skycell version of a named camera configuration
-bool pmConfigCameraSkycellVersion(psMetadata *system, // The system configuration
-                                  const char *name // Name of the un-mosaicked camera
-                                  )
-{
-    PS_ASSERT_METADATA_NON_NULL(system, false);
-    PS_ASSERT_STRING_NON_EMPTY(name, false);
-
-    bool mdok;                          // Status of MD lookup
-    psMetadata *cameras = psMetadataLookupMetadata(&mdok, system, "CAMERAS"); // List of cameras
-    if (!mdok || !cameras) {
-        psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the system configuration.\n");
-        return false;
-    }
-    if (!pmConfigGenerateSkycellVersion(cameras, cameras, name, system)) {
-        psError(PS_ERR_UNKNOWN, true, "Failed to build skycell camera description for %s\n", name);
-        return false;
-    }
-    return true;
+psString pmConfigCameraRootName(const char *name)
+{
+    PS_ASSERT_STRING_NON_EMPTY(name, NULL);
+
+    if (name[0] != '_') {
+        // It's an original
+        return psStringCopy(name);
+    }
+
+    psString root = psStringCopy(name + 1); // Camera name
+    int length = strlen(name);                     // Length of camera name
+    if (strcmp(root + length - 9, "-SKYCELL") == 0) {
+        length -= 9;
+    } else if (strcmp(root + length - 6, "-CHIP") == 0) {
+        length -= 6;
+    } else if (strcmp(root + length - 5, "-FPA") == 0) {
+        length -= 5;
+    } else {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unrecognised derivative camera: %s", name);
+        psFree(root);
+        return NULL;
+    }
+
+    // Truncate the string
+    root[length] = '\0';
+
+    return root;
+}
+
+psString pmConfigCameraSkycellName(const char *name)
+{
+    PS_ASSERT_STRING_NON_EMPTY(name, NULL);
+
+    psString root = pmConfigCameraRootName(name); // Root name of camera
+    if (!root) {
+        return NULL;
+    }
+
+    psStringAppend(&root, "-SKYCELL");
+    psStringPrepend(&root, "_");
+
+    return root;
+}
+
+psString pmConfigCameraChipName(const char *name)
+{
+    PS_ASSERT_STRING_NON_EMPTY(name, NULL);
+
+    psString root = pmConfigCameraRootName(name); // Root name of camera
+    if (!root) {
+        return NULL;
+    }
+
+    psStringAppend(&root, "-CHIP");
+    psStringPrepend(&root, "_");
+
+    return root;
+}
+
+psString pmConfigCameraFPAName(const char *name)
+{
+    PS_ASSERT_STRING_NON_EMPTY(name, NULL);
+
+    psString root = pmConfigCameraRootName(name); // Root name of camera
+    if (!root) {
+        return NULL;
+    }
+
+    psStringAppend(&root, "-FPA");
+    psStringPrepend(&root, "_");
+
+    return root;
 }
 
