IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 12564


Ignore:
Timestamp:
Mar 22, 2007, 5:09:53 PM (19 years ago)
Author:
Paul Price
Message:

When we went to process TC3 images, we found that our camera formats
didn't handle its case (PHU=CHIP, EXT=CELL) properly. In order to
accomodate it, I've reworked the camera formats (including adding a
source to an FPA, and generating mosaic camera configurations). Now,
the particular format of the camera format file is *very* dependent
upon the FITS file:

Case PHU EXTENSIONS Description

  1. FPA CHIP CONTENTS(METADATA) has a list of extensions, each with a chip type.

CHIPS(METADATA) has a list of chip types, each with cell:type

  1. FPA CELL CONTENTS(METADATA) has a list of extensions, each with chip:cell:type

No need for CHIPS.

  1. FPA NONE CONTENTS(STRING) has a list of extensions, chip:cell:type

No need for CHIPS

  1. CHIP CELL CONTENTS(METADATA) is a menu, each with a chip type

CHIPS(METADATA) has a list of chip types(METADATA), containg a list of
extensions.

  1. CHIP NONE CONTENTS(METADATA) is a menu, each with a chip type

CHIPS(METADATA) has a list of chip types(STRING) with cell:type

  1. CELL NONE CONTENTS(METADATA) is a menu, each with a cell type.

No need for CHIPS.

Debugged and plugged memory leaks for this fix. Now able to
successfully read TC3 and Megacam (all 3 formats). Can't run ppImage
with PPIMAGE_N on file with PHU=CHIP because it's trying to write out
a PHU (at the FPA level) before it reads any of the input data. This
behaviour exists in a previous version (IPP 1.0; in fact, the current
fix deals with it a bit better --- error instead of SEGV), so it
should be safe to use this now.

Location:
trunk/psModules/src
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/psModules/src/camera/pmFPAConstruct.c

    r11801 r12564  
    1717#include "pmHDUUtils.h"
    1818
     19
     20#define TABLE_OF_CONTENTS "CONTENTS"    // Name for camera format metadata containing the contents
     21#define CHIP_TYPES "CHIPS"              // Name for camera format metadata containing the chip types
     22#define CELL_TYPES "CELLS"              // Name for camera format metadata containing the cell types
     23
     24
    1925//////////////////////////////////////////////////////////////////////////////////////////////////////////////
    2026// File-static functions
     
    3036
    3137    bool status = true;                 // Result of MD lookup
    32     psMetadata *cells = psMetadataLookupMetadata(&status, format, "CELLS"); // The CELLS
     38    psMetadata *cells = psMetadataLookupMetadata(&status, format, CELL_TYPES); // The CELLS
    3339    if (!status || !cells) {
    34         psError(PS_ERR_IO, true, "Unable to determine CELLS of camera.\n");
     40        psError(PS_ERR_IO, true, "Unable to find %s in camera format.\n", CELL_TYPES);
    3541        return NULL;
    3642    }
     
    4551
    4652// Parse a list of first:second:third pairs in a string
    47 static bool parseContent(psArray **first, // Array of the first values
     53static int parseContent(psArray **first, // Array of the first values
    4854                         psArray **second, // Array of the second values
    4955                         psArray **third, // Array of the third values
     
    5157                        )
    5258{
    53     assert(first);
    54     assert(second);
    55     assert(third);
    5659    assert(string && strlen(string) > 0);
    57 
    58     bool allOK = true;                  // Everything was OK?
     60    // Must populate 'first', 'second', 'third' in order.
     61    assert(!second || first);
     62    assert(!third || second);
     63
     64    int numArrays = third ? 3 : (second ? 2 : 1); // Number of arrays
     65
    5966    psList *values = psStringSplit(string, " ,;", true); // List of the parts
    60     *first = psArrayAlloc(values->n);
    61     *second = psArrayAlloc(values->n);
    62     *third = psArrayAlloc(values->n);
     67
     68    if (first) {
     69        *first = psArrayAlloc(values->n);
     70    }
     71    if (second) {
     72        *second = psArrayAlloc(values->n);
     73    }
     74    if (third) {
     75        *third = psArrayAlloc(values->n);
     76    }
    6377    int num = 0;
    6478    psListIterator *valuesIter = psListIteratorAlloc(values, PS_LIST_HEAD, false); // Iterator for values
    6579    psString value = NULL;               // "first:second:third" string
    6680    while ((value = psListGetAndIncrement(valuesIter))) {
    67         psList *firstSecondThird = psStringSplit(value, ":", true); // List containing the first, second, third
    68         psArray *fst = psListToArray(firstSecondThird); // An array representation
    69         psFree(firstSecondThird);
    70         psString firstPart = NULL;      // The first part
    71         psString secondPart = NULL;     // The second part
    72         psString thirdPart = NULL;      // The third part
    73         switch (firstSecondThird->n) {
    74         case 1:
    75             thirdPart = fst->data[0];
    76             break;
    77         case 2:
    78             secondPart = fst->data[0];
    79             thirdPart = fst->data[1];
    80             break;
    81         case 3:
    82             firstPart = fst->data[0];
    83             secondPart = fst->data[1];
    84             thirdPart = fst->data[2];
     81        psArray *fst = psStringSplitArray(value, ":", true); // First, second, third
     82        switch (numArrays) {
     83          case 3:
     84            psArraySet(*third, num, fst->data[2]);
     85          case 2:
     86            psArraySet(*second, num, fst->data[1]);
     87          case 1:
     88            psArraySet(*first, num, fst->data[0]);
    8589            break;
    8690        default:
    87             psLogMsg(__func__, PS_LOG_WARN, "Badly formated specifier: %s --- ignored.\n", value);
    88             allOK = false;
    89             psFree(fst);
    90             continue;
    91         }
    92         psArraySet(*first, num, firstPart);
    93         psArraySet(*second, num, secondPart);
    94         psArraySet(*third, num, thirdPart);
     91          psAbort("Should never get here.");
     92        }
    9593        num++;
    9694        psFree(fst);
     
    9997    psFree(values);
    10098
    101     return allOK;
     99    return num;
    102100}
    103101
     
    268266
    269267
    270 // Given a (string) list of contents "chip:cell:type chip:cell:type", put the HDU in the correct place and
    271 // plug in the cell configuration information
    272 static int processContents(pmFPA *fpa,  // The FPA
    273                            pmChip *chip, // The chip, or NULL
    274                            pmCell *cell, // The cell, or NULL
    275                            pmHDU *hdu,  // The HDU to be added
    276                            pmFPALevel level, // The level at which to add the HDU
    277                            const char *contents, // The contents line, consisting of a list of chip:cell
    278                            const psMetadata *format // Camera format configuration
    279                           )
     268// Given a list of contents, put the HDU in the correct place and plug in the cell configuration information
     269static bool processContents(pmFPA *fpa,  // The FPA
     270                            pmChip *chip, // The chip
     271                            pmCell *cell, // The cell
     272                            pmHDU *hdu,  // The HDU to be added
     273                            pmFPALevel level, // The level at which to add the HDU
     274                            psArray *chipNames, // The chip names
     275                            psArray *cellNames, // The cell names
     276                            psArray *cellTypes, // The cell types
     277                            const psMetadata *format // Camera format configuration
     278                            )
    280279{
    281280    assert(fpa);
    282     assert(contents && strlen(contents) > 0);
    283     assert(!cell || (cell && chip));    // Need both chip and cell if given a cell
     281    assert(cellTypes);
     282    long num = cellTypes->n;            // Number of entries to add
     283    assert(chip || (chipNames && chipNames->n == num));
     284    assert(cell || (cellNames && cellNames->n == num));
    284285    assert(format);
    285286
    286287    if (hdu && level == PM_FPA_LEVEL_FPA) {
    287288        if (!addHDUtoFPA(fpa, hdu)) {
    288             psError(PS_ERR_UNKNOWN, false, "Adding HDU to FPA (%s)", contents);
    289             return -1;
    290         }
    291     }
    292 
    293     // Parse the list of chip:cell:type
    294     psArray *chips = NULL;              // The chips (first bits)
    295     psArray *cells = NULL;              // The cells (second bits)
    296     psArray *types = NULL;              // The cell types (third bits)
    297     int numCells = 0;                   // Number of cells processed
    298     parseContent(&chips, &cells, &types, contents);
    299     for (int i = 0; i < types->n; i++) {
    300         psString chipName = chips->data[i]; // The name of the chip
    301         psString cellName = cells->data[i]; // The name of the cell
    302         psString cellType = types->data[i]; // The type of the cell
    303 
    304         // Get the chip
    305         pmChip *newChip = NULL;         // The chip specified
     289            psError(PS_ERR_UNKNOWN, false, "Unable to add HDU to FPA");
     290            return false;
     291        }
     292    }
     293    // Load fpa-related concepts
     294    if (!pmConceptsReadFPA(fpa, PM_CONCEPT_SOURCE_DEFAULTS, false, NULL)) {
     295        psError(PS_ERR_UNKNOWN, false, "Unable to read concepts from camera and defaults for fpa\n");
     296        return false;
     297    }
     298
     299    for (int i = 0; i < num; i++) {
     300        psString cellType = cellTypes->data[i]; // The type of the cell
     301
     302        // Find the chip
     303        pmChip *newChip;                // Chip of interest
    306304        if (chip) {
    307305            newChip = chip;
    308         } else if (chipName) {
    309             // Find the chip
     306        } else {
     307            psString chipName = chipNames->data[i]; // The name of the chip
    310308            int chipNum = pmFPAFindChip(fpa, chipName); // The chip we're looking for
    311309            if (chipNum == -1) {
    312                 psLogMsg(__func__, PS_LOG_WARN, "Unable to find chip %s in fpa --- ignored.\n", chipName);
    313                 continue;
     310                psError(PS_ERR_LOCATION_INVALID, false,
     311                        "Unable to find chip %s in fpa --- ignored.\n", chipName);
     312                return false;
    314313            }
    315314            newChip = fpa->chips->data[chipNum];
    316         }
    317 
    318         if (!newChip) {
    319             psLogMsg(__func__, PS_LOG_WARN, "Unable to determine chip for entry %d of content (follows) --- "
    320                      "ignored.\n\t%s", i, contents);
    321             continue;
    322315        }
    323316
     
    326319            addHDUtoChip(newChip, hdu);
    327320        }
    328         // load chip-related concepts
     321        // Load chip-related concepts
    329322        if (!pmConceptsReadChip(newChip, PM_CONCEPT_SOURCE_DEFAULTS, false, false, NULL)) {
    330             psError(PS_ERR_UNKNOWN, false, "Unable to read concepts from camera and defaults for chip %s\n",
    331                     chipName);
    332             return -1;
    333         }
    334 
    335         // Get the cell
    336         pmCell *newCell = NULL;         // The cell specified
     323            psError(PS_ERR_UNKNOWN, false, "Unable to read concepts from camera and defaults for chip\n");
     324            return false;
     325        }
     326
     327        // Find the cell
     328        pmCell *newCell;                // Cell of interest
    337329        if (cell) {
    338330            newCell = cell;
    339         } else if (cellName) {
    340             // Find the cell
     331        } else {
     332            psString cellName = cellNames->data[i]; // The name of the cell
    341333            int cellNum = pmChipFindCell(newChip, cellName); // The cell we're looking for
    342334            if (cellNum == -1) {
    343                 psLogMsg(__func__, PS_LOG_WARN, "Unable to find cell %s in chip %s --- ignored.\n",
    344                          cellName, chipName);
    345                 continue;
     335                psError(PS_ERR_LOCATION_INVALID, false, "Unable to find cell %s in chip --- ignored.\n",
     336                        cellName);
     337                return false;
    346338            }
    347339            newCell = newChip->cells->data[cellNum];
    348340        }
    349         if (!newCell) {
    350             psLogMsg(__func__, PS_LOG_WARN, "Unable to determine cell for entry %d of content (follows) --- "
    351                      "ignored.\n\t%s", i, contents);
    352             continue;
    353         }
    354 
    355         // Get the type
    356         if (!cellType) {
    357             psLogMsg(__func__, PS_LOG_WARN, "Unable to determine cell type for entry %d of content (follows) "
    358                      "--- ignored.\n\t%s", i, contents);
    359             continue;
    360         }
     341
    361342        psMetadata *cellData = getCellData(format, cellType); // Data for this cell
    362343
     
    367348        // Put in the cell data
    368349        if (newCell->config) {
    369             psLogMsg(__func__, PS_LOG_WARN, "Overwriting cell data in chip %s, cell %s\n", chipName,
    370                      cellName);
     350            psLogMsg(__func__, PS_LOG_WARN, "Overwriting cell data in chip\n");
    371351            psFree(newCell->config); // Make way!
    372352        }
     
    374354        if (!pmConceptsReadCell(newCell, PM_CONCEPT_SOURCE_CELLS | PM_CONCEPT_SOURCE_DEFAULTS,
    375355                                false, NULL)) {
    376             psError(PS_ERR_UNKNOWN, false, "Unable to read concepts from camera and defaults for chip %s, "
    377                     "cell %s, type %s", chipName, cellName, cellType);
    378             return -1;
    379         }
    380         numCells++;
    381     }
    382     psFree(chips);
    383     psFree(cells);
    384     psFree(types);
    385 
    386     return numCells;
    387 }
    388 
     356            psError(PS_ERR_UNKNOWN, false,
     357                    "Unable to read concepts from camera and defaults for cell type %s", cellType);
     358            return false;
     359        }
     360    }
     361
     362    return true;
     363}
     364
     365#if 0
    389366// Return the level at which EXTENSIONS go, from the FILE metadata within the camera format
    390367static pmFPALevel hduLevel(const psMetadata *format // The camera format configuration
     
    418395    return level;
    419396}
    420 
    421 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
    422 // Public functions
    423 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
    424 
    425 pmFPA *pmFPAConstruct(const psMetadata *camera)
    426 {
    427     PS_ASSERT_PTR_NON_NULL(camera, NULL);
    428 
    429     pmFPA *fpa = pmFPAAlloc(camera);    // The FPA to fill out
    430 
    431     bool mdok = true;                   // Status from MD lookups
    432     psMetadata *components = psMetadataLookupMetadata(&mdok, camera, "FPA"); // FPA components
    433     if (!mdok || !components) {
    434         psError(PS_ERR_IO, true, "Failed to lookup \"FPA\"");
    435         psFree(fpa);
     397#endif
     398
     399// Find the chip of interest within the FPA, using either the view (simple) or the FITS header (bit more
     400// complicated).  Also updates the provided view to point to the chip if we have to find it.
     401static pmChip *whichChip(pmFPAview *view, // View to chip, modified
     402                         const pmFPA *fpa, // FPA holding chip of interest
     403                         const pmFPAview *phuView, // View to PHU, or NULL
     404                         const psMetadata *fileInfo, // FILE information from camera format
     405                         const psMetadata *header // FITS header, or NULL
     406                         )
     407{
     408    assert(view);
     409    assert(fpa);
     410    assert(phuView || header);
     411    assert(fileInfo);
     412
     413    if (phuView) {
     414        return pmFPAviewThisChip(phuView, fpa);
     415    }
     416
     417    psString chipName = phuNameFromHeader("CHIP.NAME", fileInfo, header);
     418    psTrace("psModules.camera", 5, "This is chip %s\n", chipName);
     419    int chipNum = pmFPAFindChip(fpa, chipName); // Chip number
     420    if (chipNum == -1) {
     421        psError(PS_ERR_UNKNOWN, true, "Unable to find chip %s in FPA.\n", chipName);
    436422        return NULL;
    437423    }
    438     psMetadataIterator *componentsIter = psMetadataIteratorAlloc(components, PS_LIST_HEAD, NULL);
    439     psMetadataItem *componentsItem = NULL; // Item from components
    440     while ((componentsItem = psMetadataGetAndIncrement(componentsIter))) {
    441         const char *chipName = componentsItem->name; // Name of the chip
    442         if (componentsItem->type != PS_DATA_STRING) {
    443             psLogMsg(__func__, PS_LOG_WARN, "Element %s in FPA within the camera configuration is not of "
    444                      "type STR (type=%x) --- ignored.\n", chipName, componentsItem->type);
    445             continue;
    446         }
    447 
    448         pmChip *chip = pmChipAlloc(fpa, chipName); // The chip
    449         psList *cellNames = psStringSplit(componentsItem->data.V, " ,;", true); // List of cell names
    450         psListIterator *cellNamesIter = psListIteratorAlloc(cellNames, PS_LIST_HEAD, false); // Iterator
    451 
    452         psString cellName = NULL;       // Name of cell
    453         while ((cellName = psListGetAndIncrement(cellNamesIter))) {
    454             pmCell *cell = pmCellAlloc(chip, cellName); // New cell
    455             psFree(cell);               // Drop reference
    456         }
    457         psFree(chip);                   // Drop reference
    458         psFree(cellNamesIter);
     424    psFree(chipName);
     425    view->chip = chipNum;
     426    return fpa->chips->data[chipNum];
     427}
     428
     429// Find the cell of interest within the chip, using either the view (simple) or the FITS header (bit more
     430// complicated).  Also updates the provided view to point to the cell if we have to find it.
     431static pmCell *whichCell(pmFPAview *view, // View to cell
     432                         const pmChip *chip, // Chip holding cell of interest
     433                         const pmFPAview *phuView, // View to PHU, or NULL
     434                         const psMetadata *fileInfo, // FILE information from camera format
     435                         const psMetadata *header // FITS header, or NULL
     436                         )
     437{
     438    assert(view);
     439    assert(chip);
     440    assert(phuView || header);
     441    assert(fileInfo);
     442
     443    pmFPA *fpa = chip->parent;          // The parent FPA
     444
     445    if (phuView) {
     446        return pmFPAviewThisCell(phuView, fpa);
     447    }
     448
     449    psString cellName = phuNameFromHeader("CELL.NAME", fileInfo, header);
     450    psTrace("psModules.camera", 5, "This is cell %s\n", cellName);
     451    int cellNum = pmChipFindCell(chip, cellName); // Cell number
     452    if (cellNum == -1) {
     453        psError(PS_ERR_UNKNOWN, true, "Unable to find cell %s in chip.\n", cellName);
     454        return NULL;
     455    }
     456    view->cell = cellNum;
     457    return chip->cells->data[cellNum];
     458}
     459
     460
     461// PHU=FPA and EXTENSIONS=CHIP:
     462// TABLE_OF_CONTENTS(METADATA) has a list of extensions, each with a chipName:chipType.
     463// CHIP_TYPES(METADATA) has a list of chip types, each with cellName:cellType
     464static bool addSource_FPA_CHIP(pmFPA *fpa, // FPA to which to add
     465                               const psMetadata *format // The camera format
     466                               )
     467{
     468    assert(fpa);
     469    assert(format);
     470
     471    psMetadata *contents = psMetadataLookupMetadata(NULL, format, TABLE_OF_CONTENTS); // The contents
     472    if (!contents) {
     473        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find %s in camera format.", TABLE_OF_CONTENTS);
     474        return false;
     475    }
     476
     477    psMetadata *chips = psMetadataLookupMetadata(NULL, format, CHIP_TYPES); // The chip types
     478    if (!chips) {
     479        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find %s in camera format.", CHIP_TYPES);
     480        return false;
     481    }
     482
     483    // Iterate over all extensions
     484    psMetadataIterator *contentsIter = psMetadataIteratorAlloc(contents, PS_LIST_HEAD, NULL); // Iterator
     485    psMetadataItem *item;               // Item from iteration
     486    while ((item = psMetadataGetAndIncrement(contentsIter))) {
     487        if (item->type != PS_DATA_STRING) {
     488            psError(PS_ERR_BAD_PARAMETER_TYPE, true,
     489                    "Type for %s (%x) in %s METADATA in camera format is not STR",
     490                    item->name, item->type, TABLE_OF_CONTENTS);
     491            psFree(contentsIter);
     492            return false;
     493        }
     494
     495        const char *extname = item->name; // Extension name
     496        pmHDU *hdu = pmHDUAlloc(extname); // HDU for this extension
     497        // Casting to avoid "warning: passing arg 1 of `p_psMemIncrRefCounter' discards qualifiers from
     498        // pointer target type"
     499        hdu->format = psMemIncrRefCounter((const psPtr)format);
     500
     501        // What's in the extension?  It's specified by chipName:chipType
     502        // Assume that an extension contains only a single chip, instead of multiple chips
     503
     504        psString extContents = item->data.str; // Contents of extension
     505        psArray *chipNames = NULL;
     506        psArray *chipTypes = NULL;
     507        if (parseContent(&chipNames, &chipTypes, NULL, extContents) != 1) {
     508            psError(PS_ERR_UNKNOWN, false,
     509                    "Unable to parse chipName:chipType in %s of %s in camera format",
     510                    extname, TABLE_OF_CONTENTS);
     511        }
     512
     513        psString chipName = psMemIncrRefCounter(chipNames->data[0]); // Name of chip
     514        psString chipType = psMemIncrRefCounter(chipTypes->data[0]); // Type of chip
     515        psFree(chipNames);
     516        psFree(chipTypes);
     517
     518        // Get the chip
     519        int chipNum = pmFPAFindChip(fpa, chipName); // Chip number
     520        if (chipNum == -1) {
     521            psError(PS_ERR_UNKNOWN, false, "Unable to find chip %s in FPA.\n", chipName);
     522            psFree(hdu);
     523            psFree(contentsIter);
     524            return false;
     525        }
     526        pmChip *chip = fpa->chips->data[chipNum]; // Chip of interest
     527
     528        // What's in the chip?
     529
     530        psString chipContents = psMetadataLookupStr(NULL, chips, chipType); // Contents of the chip
     531        if (!chipContents) {
     532            psError(PS_ERR_UNEXPECTED_NULL, false,
     533                    "Unable to find chip type %s (for extension %s) in %s of camera format",
     534                    chipType, extname, CHIP_TYPES);
     535            psFree(chipName);
     536            psFree(chipType);
     537            psFree(hdu);
     538            psFree(contentsIter);
     539            return false;
     540        }
     541
     542        psArray *cellNames = NULL;      // Cell names
     543        psArray *cellTypes = NULL;      // Cell types
     544        if (parseContent(&cellNames, &cellTypes, NULL, chipContents) == 0) {
     545            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
     546                    "Unable to parse chip contents (within %s->%s in camera format; for chip %s) "
     547                    "as cellName:cellType", CHIP_TYPES, chipType, chipName);
     548            psFree(cellNames);
     549            psFree(cellTypes);
     550            psFree(chipName);
     551            psFree(chipType);
     552            psFree(hdu);
     553            psFree(contentsIter);
     554            return false;
     555        }
     556
     557        if (!processContents(fpa, chip, NULL, hdu, PM_FPA_LEVEL_CHIP, NULL, cellNames, cellTypes, format)) {
     558            psError(PS_ERR_UNKNOWN, false, "Unable to set contents for chip %s from camera format.",
     559                    chipName);
     560            psFree(cellNames);
     561            psFree(cellTypes);
     562            psFree(chipName);
     563            psFree(chipType);
     564            psFree(hdu);
     565            psFree(contentsIter);
     566            return false;
     567        }
     568
    459569        psFree(cellNames);
    460     }
    461     psFree(componentsIter);
    462 
    463     return fpa;
     570        psFree(cellTypes);
     571        psFree(chipName);
     572        psFree(chipType);
     573
     574        psFree(hdu);                    // Drop reference
     575    }
     576    psFree(contentsIter);
     577
     578    return true;
     579}
     580
     581// PHU=FPA and EXTENSIONS=CELL:
     582// TABLE_OF_CONTENTS(METADATA) has a list of extensions, each with a chipName:cellName:cellType.
     583static bool addSource_FPA_CELL(pmFPA *fpa, // FPA to which to add
     584                               const psMetadata *format // The camera format
     585                               )
     586{
     587    assert(fpa);
     588    assert(format);
     589
     590    psMetadata *contents = psMetadataLookupMetadata(NULL, format, TABLE_OF_CONTENTS); // The contents
     591    if (!contents) {
     592        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find %s in camera format.", TABLE_OF_CONTENTS);
     593        return false;
     594    }
     595
     596    // Iterate over all extensions
     597    psMetadataIterator *contentsIter = psMetadataIteratorAlloc(contents, PS_LIST_HEAD, NULL); // Iterator
     598    psMetadataItem *item;               // Item from iteration
     599    while ((item = psMetadataGetAndIncrement(contentsIter))) {
     600        if (item->type != PS_DATA_STRING) {
     601            psError(PS_ERR_BAD_PARAMETER_TYPE, true,
     602                    "Type for %s (%x) in %s METADATA in camera format is not STR",
     603                    item->name, item->type, TABLE_OF_CONTENTS);
     604            psFree(contentsIter);
     605            return false;
     606        }
     607
     608        const char *extname = item->name; // Extension name
     609        pmHDU *hdu = pmHDUAlloc(extname); // HDU for this extension
     610        // Casting to avoid "warning: passing arg 1 of `p_psMemIncrRefCounter' discards qualifiers from
     611        // pointer target type"
     612        hdu->format = psMemIncrRefCounter((const psPtr)format);
     613
     614        // What's in the extension?  It's specified by (possibly multiple) chipName:cellName:cellType
     615
     616        psArray *chipNames = NULL;      // Chip names
     617        psArray *cellNames = NULL;      // Cell names
     618        psArray *cellTypes = NULL;      // Cell types
     619        if (parseContent(&chipNames, &cellNames, &cellTypes, item->data.str) == 0) {
     620            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
     621                    "Unable to parse extension contents (within %s->%s in camera format) as "
     622                    "chipName:cellName:cellType", TABLE_OF_CONTENTS, extname);
     623            psFree(chipNames);
     624            psFree(cellNames);
     625            psFree(cellTypes);
     626            psFree(hdu);
     627            psFree(contentsIter);
     628            return false;
     629        }
     630
     631        if (!processContents(fpa, NULL, NULL, hdu, PM_FPA_LEVEL_CELL, chipNames, cellNames, cellTypes,
     632                             format)) {
     633            psError(PS_ERR_UNKNOWN, false, "Unable to set contents from camera format.");
     634            psFree(chipNames);
     635            psFree(cellNames);
     636            psFree(cellTypes);
     637            psFree(hdu);
     638            psFree(contentsIter);
     639            return false;
     640        }
     641
     642        psFree(chipNames);
     643        psFree(cellNames);
     644        psFree(cellTypes);
     645
     646        psFree(hdu);                    // Drop reference
     647    }
     648    psFree(contentsIter);
     649
     650    return true;
     651}
     652
     653// PHU=FPA and EXTENSIONS=NONE:
     654// TABLE_OF_CONTENTS(STR) has a list of chipName:cellName:cellType.
     655static bool addSource_FPA_NONE(pmFPA *fpa, // FPA to which to add
     656                               const psMetadata *format // The camera format
     657                               )
     658{
     659    assert(fpa);
     660    assert(format);
     661
     662    psString contents = psMetadataLookupStr(NULL, format, TABLE_OF_CONTENTS); // The contents
     663    if (!contents) {
     664        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find %s in camera format.", TABLE_OF_CONTENTS);
     665        return false;
     666    }
     667
     668    // What's in the file?  It's specified by (possibly multiple) chipName:cellName:cellType
     669
     670    psArray *chipNames = NULL;          // Chip names
     671    psArray *cellNames = NULL;          // Cell names
     672    psArray *cellTypes = NULL;          // Cell types
     673    if (parseContent(&chipNames, &cellNames, &cellTypes, contents) == 0) {
     674        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
     675                "Unable to parse contents (within %s in camera format) as chipName:cellName:cellType",
     676                TABLE_OF_CONTENTS);
     677        psFree(chipNames);
     678        psFree(cellNames);
     679        psFree(cellTypes);
     680        return false;
     681    }
     682
     683    if (!processContents(fpa, NULL, NULL, NULL, PM_FPA_LEVEL_NONE, chipNames, cellNames, cellTypes,
     684                         format)) {
     685        psError(PS_ERR_UNKNOWN, false, "Unable to set contents from camera format.");
     686        psFree(chipNames);
     687        psFree(cellNames);
     688        psFree(cellTypes);
     689        return false;
     690    }
     691
     692    psFree(chipNames);
     693    psFree(cellNames);
     694    psFree(cellTypes);
     695
     696    return true;
     697}
     698
     699
     700// PHU=CHIP and EXTENSIONS=CELL:
     701// TABLE_OF_CONTENTS(METADATA) has a menu of contents, each with a chipType.
     702// CHIP_TYPES(METADATA) has a list of chip types, each with extension(METADATA) with cellName:cellType
     703static bool addSource_CHIP_CELL(pmChip *chip, // Chip to which to add
     704                                const psMetadata *format // The camera format
     705                                )
     706{
     707    assert(chip);
     708    assert(format);
     709
     710    psMetadata *contents = psMetadataLookupMetadata(NULL, format, TABLE_OF_CONTENTS); // The contents
     711    if (!contents) {
     712        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find %s in camera format.", TABLE_OF_CONTENTS);
     713        return false;
     714    }
     715
     716    psMetadata *chips = psMetadataLookupMetadata(NULL, format, CHIP_TYPES); // The chip types
     717    if (!chips) {
     718        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find %s in camera format.", CHIP_TYPES);
     719        return false;
     720    }
     721
     722    psMetadata *fileInfo = psMetadataLookupMetadata(NULL, format, "FILE"); // The file information
     723    if (!fileInfo) {
     724        psError(PS_ERR_IO, false, "Unable to find FILE in the camera format configuration.\n");
     725        return false;
     726    }
     727
     728    const char *chipType = getContent(fileInfo, contents, chip, NULL); // The chip type
     729
     730    // What's in the chip?
     731
     732    psMetadata *chipContents = psMetadataLookupMetadata(NULL, chips, chipType); // Contents of the chip
     733    if (!chipContents) {
     734        psError(PS_ERR_UNEXPECTED_NULL, false,
     735                "Unable to find chip type %s in %s of camera format",
     736                chipType, CHIP_TYPES);
     737        return false;
     738    }
     739
     740    pmFPA *fpa = chip->parent;          // The parent FPA
     741
     742    psMetadataIterator *contentsIter = psMetadataIteratorAlloc(chipContents, PS_LIST_HEAD, NULL); // Iterator
     743    psMetadataItem *contentItem;        // Content, from iteration
     744    while ((contentItem = psMetadataGetAndIncrement(contentsIter))) {
     745        if (contentItem->type != PS_DATA_STRING) {
     746            psError(PS_ERR_BAD_PARAMETER_TYPE, true,
     747                    "Type for %s (%x) in %s METADATA in camera format is not STR",
     748                    contentItem->name, contentItem->type, TABLE_OF_CONTENTS);
     749            psFree(contentsIter);
     750            return false;
     751        }
     752
     753        const char *extname = contentItem->name; // Extension name
     754        pmHDU *hdu = pmHDUAlloc(extname); // HDU for this extension
     755        // Casting to avoid "warning: passing arg 1 of `p_psMemIncrRefCounter' discards qualifiers from
     756        // pointer target type"
     757        hdu->format = psMemIncrRefCounter((const psPtr)format);
     758
     759        psArray *cellNames = NULL;      // Cell names
     760        psArray *cellTypes = NULL;      // Cell types
     761        if (parseContent(&cellNames, &cellTypes, NULL, contentItem->data.str) == 0) {
     762            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
     763                    "Unable to parse chip contents (within %s->%s in camera format) "
     764                    "as cellName:cellType", CHIP_TYPES, chipType);
     765            psFree(cellNames);
     766            psFree(cellTypes);
     767            psFree(hdu);
     768            psFree(contentsIter);
     769            return false;
     770        }
     771
     772        if (!processContents(fpa, chip, NULL, hdu, PM_FPA_LEVEL_CELL, NULL, cellNames, cellTypes, format)) {
     773            psError(PS_ERR_UNKNOWN, false, "Unable to set contents for chip type %s from camera format.",
     774                    chipType);
     775            psFree(cellNames);
     776            psFree(cellTypes);
     777            psFree(hdu);
     778            psFree(contentsIter);
     779            return false;
     780        }
     781
     782        psFree(cellNames);
     783        psFree(cellTypes);
     784
     785        psFree(hdu);                    // Drop reference
     786    }
     787    psFree(contentsIter);
     788
     789    return true;
     790}
     791
     792// PHU=CHIP and EXTENSIONS=NONE:
     793// TABLE_OF_CONTENTS(METADATA) has a menu of contents, each with a chipName:chipType.
     794// CHIP_TYPES(METADATA) has a list of chip types, each with cellName:cellType
     795static bool addSource_CHIP_NONE(pmChip *chip, // Chip to which to add
     796                                const psMetadata *format // The camera format
     797                                )
     798{
     799    assert(chip);
     800    assert(format);
     801
     802    psMetadata *contents = psMetadataLookupMetadata(NULL, format, TABLE_OF_CONTENTS); // The contents
     803    if (!contents) {
     804        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find %s in camera format.", TABLE_OF_CONTENTS);
     805        return false;
     806    }
     807
     808    psMetadata *chips = psMetadataLookupMetadata(NULL, format, CHIP_TYPES); // The chip types
     809    if (!chips) {
     810        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find %s in camera format.", CHIP_TYPES);
     811        return false;
     812    }
     813
     814    psMetadata *fileInfo = psMetadataLookupMetadata(NULL, format, "FILE"); // The file information
     815    if (!fileInfo) {
     816        psError(PS_ERR_IO, false, "Unable to find FILE in the camera format configuration.\n");
     817        return false;
     818    }
     819
     820    pmFPA *fpa = chip->parent;          // Parent FPA
     821
     822    const char *chipType = getContent(fileInfo, contents, chip, NULL); // The chip type
     823
     824    // What's in the chip?
     825
     826    psString chipContents = psMetadataLookupStr(NULL, chips, chipType); // Contents of the chip
     827    if (!chipContents) {
     828        psError(PS_ERR_UNEXPECTED_NULL, false,
     829                "Unable to find chip type %s in %s of camera format", chipType, CHIP_TYPES);
     830        return false;
     831    }
     832
     833    psArray *cellNames = NULL;      // Cell names
     834    psArray *cellTypes = NULL;      // Cell types
     835    if (parseContent(&cellNames, &cellTypes, NULL, chipContents) == 0) {
     836        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
     837                "Unable to parse chip contents (within %s->%s in camera format) "
     838                "as cellName:cellType", CHIP_TYPES, chipType);
     839        psFree(cellNames);
     840        psFree(cellTypes);
     841        return false;
     842    }
     843
     844    if (!processContents(fpa, chip, NULL, NULL, PM_FPA_LEVEL_NONE, NULL, cellNames, cellTypes, format)) {
     845        psError(PS_ERR_UNKNOWN, false, "Unable to set contents for chip type %s from camera format.",
     846                chipType);
     847        psFree(cellNames);
     848        psFree(cellTypes);
     849        return false;
     850    }
     851
     852    psFree(cellNames);
     853    psFree(cellTypes);
     854
     855    return true;
     856}
     857
     858// PHU=CELL and EXTENSIONS=NONE:
     859// TABLE_OF_CONTENTS(METADATA) has a menu of contents, each with a cellName:cellType
     860static bool addSource_CELL_NONE(pmCell *cell, // Cell to which to add
     861                                const psMetadata *format // The camera format
     862                                )
     863{
     864    assert(cell);
     865    assert(format);
     866
     867    psMetadata *contents = psMetadataLookupMetadata(NULL, format, TABLE_OF_CONTENTS); // The contents
     868    if (!contents) {
     869        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find %s in camera format.", TABLE_OF_CONTENTS);
     870        return false;
     871    }
     872
     873    psMetadata *fileInfo = psMetadataLookupMetadata(NULL, format, "FILE"); // The file information
     874    if (!fileInfo) {
     875        psError(PS_ERR_IO, false, "Unable to find FILE in the camera format configuration.\n");
     876        return false;
     877    }
     878
     879    pmChip *chip = cell->parent;        // Parent chip
     880    pmFPA *fpa = chip->parent;          // Parent FPA
     881
     882    const char *content = getContent(fileInfo, contents, chip, NULL); // Content of cell
     883
     884    psArray *cellNames = NULL;      // Cell names
     885    psArray *cellTypes = NULL;      // Cell types
     886    if (parseContent(&cellNames, &cellTypes, NULL, content) != 1) {
     887        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
     888                "Unable to parse cell contents (%s) as cellName:cellType", content);
     889        psFree(cellNames);
     890        psFree(cellTypes);
     891        return false;
     892    }
     893
     894    if (!processContents(fpa, chip, cell, NULL, PM_FPA_LEVEL_NONE, NULL, cellNames, cellTypes, format)) {
     895        psError(PS_ERR_UNKNOWN, false, "Unable to set contents for cell from camera format.");
     896        psFree(cellNames);
     897        psFree(cellTypes);
     898        return false;
     899    }
     900
     901    psFree(cellNames);
     902    psFree(cellTypes);
     903
     904    return true;
    464905}
    465906
     
    531972    // Now, there are a few cases:
    532973
    533     // 1. PHU=FPA and EXTENSIONS=NONE.  This is a single CCD imager, where the entire FPA is in the PHU image.
    534     // In this case, the CONTENTS is of type STR (rather than METADATA), and has the usual chip:cell:cellType.
    535     //
    536     // 2. PHU=CHIP or PHU=CELL, and EXTENSIONS=NONE.  This is a single chip or cell from a mosaic camera in
    537     // its own file (e.g., Megacam split).  In this case, the CONTENTS is of type METADATA, and consists of a
    538     // menu of choices for the contents of the file.  This is because we need to work out which chip and/or
    539     // cell it comes from.
    540     //
    541     // 3. EXTENSIONS=CHIP or EXTENSIONS=CELL.  This is a mosaic camera, with multiple extensions.  In this
    542     // case, the CONTENTS is of type METADATA, and consists of a list of contents of the file.
    543     //
    544     // In all of the above cases, the contents are specified by chip:cell:cellType triples.  It's just how the
    545     // contents as a *whole* are collected that changes, and what that collection means.
    546     //
    547     // We deal with each of these cases in turn.
    548 
    549     // Case 1: PHU=FPA and EXTENSIONS=NONE.  We need to parse the single list of chip:cell:cellType entries.
    550     if (strcasecmp(phuType, "FPA") == 0 && strcasecmp(extType, "NONE") == 0) {
    551         phdu->blankPHU = false;
    552         const char *contents = psMetadataLookupStr(&mdok, format, "CONTENTS"); // The contents of the file
    553         if (!mdok || !contents || strlen(contents) == 0) {
    554             psError(PS_ERR_IO, true, "Unable to find CONTENTS in the camera format configuration.\n");
    555             psFree(phdu);
    556             psFree(view);
    557             return NULL;
    558         }
    559         if (install && processContents(fpa, NULL, NULL, phdu, PM_FPA_LEVEL_FPA, contents, format) < 0) {
    560             psError(PS_ERR_IO, false, "Error setting CONTENTS");
    561             psFree(phdu);
    562             psFree(view);
    563             return NULL;
    564         }
    565         psFree(phdu);
    566 
    567         if (install && header && !pmConceptsRead(fpa, NULL, NULL, PM_CONCEPT_SOURCE_PHU, NULL)) {
    568             psWarning("Unable to read concepts from PHU.\n");
    569         }
    570 
    571         return view;
    572     }
    573 
    574     // In cases 2 and 3, the CONTENTS is of type METADATA, and is either a menu (if EXTENSIONS=NONE), or a
    575     // list of extensions otherwise.
    576     psMetadata *contents = psMetadataLookupMetadata(&mdok, format, "CONTENTS"); // The contents of the file
    577     if (!mdok || !contents) {
    578         if (mdok && !contents) {
    579             psError(PS_ERR_IO, true, "CONTENTS metadata is NULL in the camera format configuration.");
    580         } else {
    581             if(psMetadataLookup(format, "CONTENTS") != NULL) {
    582                 psError(PS_ERR_IO, true, "CONTENTS is of wrong type in camera format configuration");
    583             } else {
    584                 psError(PS_ERR_IO, true, "Unable to find CONTENTS in the camera format configuration.");
    585             }
    586         }
    587         psFree(phdu);
    588         psFree(view);
     974    // Case    PHU     EXTENSIONS     Description
     975    // ====    ===     ==========     ===========
     976    // 1.      FPA     CHIP           CONTENTS(METADATA) has a list of extensions, each with a chip type.
     977    //                                CHIPS(METADATA) has a list of chip types, each with cell:type
     978    // 2.      FPA     CELL           CONTENTS(METADATA) has a list of extensions, each with chip:cell:type
     979    //                                No need for CHIPS.
     980    // 3.      FPA     NONE           CONTENTS(STRING) has a list of extensions, chip:cell:type
     981    //                                No need for CHIPS
     982    // 4.      CHIP    CELL           CONTENTS(METADATA) is a menu, each with a chip type
     983    //                                CHIPS(METADATA) has a list of chip types(METADATA), containg a list of
     984    //                                extensions.
     985    // 5.      CHIP    NONE           CONTENTS(METADATA) is a menu, each with a chip type
     986    //                                CHIPS(METADATA) has a list of chip types(STRING) with cell:type
     987    // 6.      CELL    NONE           CONTENTS(METADATA) is a menu, each with a cell type.
     988    //                                No need for CHIPS.
     989
     990
     991    pmFPALevel phuLevel = pmFPALevelFromName(phuType); // Level for PHU
     992    pmFPALevel extLevel = pmFPALevelFromName(extType); // Level for extensions
     993
     994    switch (phuLevel) {
     995      case PM_FPA_LEVEL_FPA: {
     996          // We don't have to work out where the PHU is --- there's only one FPA.
     997          // 'view' already points to the FPA.
     998          switch (extLevel) {
     999            case PM_FPA_LEVEL_CHIP:
     1000              phdu->blankPHU = true;
     1001              if (install) {
     1002                  if (!addHDUtoFPA(fpa, phdu) || !addSource_FPA_CHIP(fpa, format)) {
     1003                      psError(PS_ERR_UNKNOWN, false, "Unable to add source.");
     1004                      psFree(phdu);
     1005                      psFree(view);
     1006                      return NULL;
     1007                  }
     1008              }
     1009              psFree(phdu);
     1010              return view;
     1011            case PM_FPA_LEVEL_CELL:
     1012              if (install) {
     1013                  phdu->blankPHU = true;
     1014                  if (!addHDUtoFPA(fpa, phdu) || !addSource_FPA_CELL(fpa, format)) {
     1015                      psError(PS_ERR_UNKNOWN, false, "Unable to add source.");
     1016                      psFree(phdu);
     1017                      psFree(view);
     1018                      return NULL;
     1019                  }
     1020              }
     1021              psFree(phdu);
     1022              return view;
     1023            case PM_FPA_LEVEL_NONE:
     1024              if (install) {
     1025                  phdu->blankPHU = false;
     1026                  if (!addHDUtoFPA(fpa, phdu) || !addSource_FPA_NONE(fpa, format)) {
     1027                      psError(PS_ERR_UNKNOWN, false, "Unable to add source.");
     1028                      psFree(phdu);
     1029                      psFree(view);
     1030                      return NULL;
     1031                  }
     1032              }
     1033              psFree(phdu);
     1034             return view;
     1035            default:
     1036              psError(PS_ERR_BAD_PARAMETER_VALUE, true,
     1037                      "EXTENSIONS level (%s) incompatible with PHU level (FPA)", extType);
     1038              psFree(phdu);
     1039              psFree(view);
     1040              return NULL;
     1041          }
     1042          break;
     1043      }
     1044      case PM_FPA_LEVEL_CHIP: {
     1045          // Which chip is our PHU?
     1046          pmChip *chip = whichChip(view, fpa, phuView, fileInfo, header); // Chip of interest
     1047          if (!chip) {
     1048              psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find chip to add.");
     1049              psFree(phdu);
     1050              psFree(view);
     1051              return NULL;
     1052          }
     1053          switch (extLevel) {
     1054            case PM_FPA_LEVEL_CELL:
     1055              if (install) {
     1056                  phdu->blankPHU = true;
     1057                  if (!addHDUtoChip(chip, phdu) || !addSource_CHIP_CELL(chip, format)) {
     1058                      psError(PS_ERR_UNKNOWN, false, "Unable to add source.");
     1059                      psFree(phdu);
     1060                      psFree(view);
     1061                      return NULL;
     1062                  }
     1063              }
     1064              psFree(phdu);
     1065              return view;
     1066            case PM_FPA_LEVEL_NONE:
     1067              if (install) {
     1068                  phdu->blankPHU = false;
     1069                  if (!addHDUtoChip(chip, phdu) || !addSource_CHIP_NONE(chip, format)) {
     1070                      psError(PS_ERR_UNKNOWN, false, "Unable to add source.");
     1071                      psFree(phdu);
     1072                      psFree(view);
     1073                      return NULL;
     1074                  }
     1075              }
     1076              psFree(phdu);
     1077              return view;
     1078            default:
     1079              psError(PS_ERR_BAD_PARAMETER_VALUE, true,
     1080                      "EXTENSIONS level (%s) incompatible with PHU level (CHIP)", extType);
     1081              return NULL;
     1082          }
     1083          break;
     1084      }
     1085      case PM_FPA_LEVEL_CELL: {
     1086          pmChip *chip = whichChip(view, fpa, phuView, fileInfo, header); // Chip of interest
     1087          if (!chip) {
     1088              psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find chip to add.");
     1089              psFree(phdu);
     1090              psFree(view);
     1091              return NULL;
     1092          }
     1093          pmCell *cell = whichCell(view, chip, phuView, fileInfo, header); // Cell of interest
     1094          if (!cell) {
     1095              psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find cell to add.");
     1096              psFree(phdu);
     1097              psFree(view);
     1098              return NULL;
     1099          }
     1100          if (extLevel != PM_FPA_LEVEL_NONE) {
     1101              psError(PS_ERR_BAD_PARAMETER_VALUE, true,
     1102                      "EXTENSIONS level (%s) incompatible with PHU level (CELL)", extType);
     1103              return NULL;
     1104          }
     1105          if (install) {
     1106              phdu->blankPHU = false;
     1107              if (!addHDUtoCell(cell, phdu) || !addSource_CELL_NONE(cell, format)) {
     1108                  psError(PS_ERR_UNKNOWN, false, "Unable to add source.");
     1109                  psFree(phdu);
     1110                  psFree(view);
     1111                  return NULL;
     1112              }
     1113          }
     1114          psFree(phdu);
     1115          return view;
     1116          break;
     1117      }
     1118      default:
     1119        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Bad PHU level: %s", phuType);
    5891120        return NULL;
    5901121    }
    5911122
    592     // Case 2: EXTENSIONS=NONE.  We only have the PHU.  The value of CONTENT tells us a header keyword, which
    593     // gives us the key to the CONTENTS menu.  Or, if we've got the view specifying the PHU, we can get the
    594     // chip/cell directly from that.
    595     if (strcasecmp(extType, "NONE") == 0) {
    596         phdu->blankPHU = false;
    597         pmChip *chip = NULL;        // The chip of interest
    598         pmCell *cell = NULL;        // The cell of interest
    599         pmFPALevel level = PM_FPA_LEVEL_NONE; // Level for HDU to be added
    600 
    601         if (phuView) {
    602             // We can get the chip/cell from the view
    603             if (phuView->chip != -1 && phuView->chip < fpa->chips->n) {
    604                 chip = fpa->chips->data[phuView->chip];
    605                 level = PM_FPA_LEVEL_CHIP;
    606                 if (phuView->cell != -1) {
    607                     if (phuView->cell < chip->cells->n) {
    608                         cell = chip->cells->data[phuView->cell];
    609                         level = PM_FPA_LEVEL_CELL;
    610                     } else {
    611                         psError(PS_ERR_BAD_PARAMETER_VALUE, true, "PHU view for cell (%d) does not "
    612                                 "correspond to camera format.\n", phuView->cell);
    613                         psFree(phdu);
    614                         return NULL;
    615                     }
    616                 }
    617             } else {
    618                 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "PHU view for chip (%d) does not correspond to "
    619                         "camera format.\n", phuView->chip);
    620                 psFree(phdu);
    621                 return NULL;
    622             }
    623         } else {
    624             // Need to look up what chip we have.
    625             psString chipName = phuNameFromHeader("CHIP.NAME", fileInfo, header);
    626             psTrace("psModules.camera", 5, "This is chip %s\n", chipName);
    627             int chipNum = pmFPAFindChip(fpa, chipName); // Chip number
    628             if (chipNum == -1) {
    629                 psError(PS_ERR_IO, true, "Unable to find chip %s in FPA.\n", chipName);
    630                 psFree(phdu);
    631                 psFree(view);
    632                 return NULL;
    633             }
    634             chip = fpa->chips->data[chipNum]; // Chip of interest
    635             view->chip = chipNum;
    636 
    637             if (strcasecmp(phuType, "CHIP") == 0) {
    638                 level = PM_FPA_LEVEL_CHIP;
    639             } else if (strcasecmp(phuType, "CELL") == 0) {
    640                 level = PM_FPA_LEVEL_CELL;
    641                 // Need to look up what cell we have.
    642                 psString cellName = phuNameFromHeader("CELL.NAME", fileInfo, header);
    643                 int cellNum = pmChipFindCell(chip, cellName); // Cell number
    644                 if (cellNum == -1) {
    645                     psError(PS_ERR_IO, true, "Unable to find cell %s in chip %s.\n", cellName, chipName);
    646                     psFree(view);
    647                     psFree(phdu);
    648                     return NULL;
    649                 }
    650                 cell = chip->cells->data[cellNum];
    651                 view->cell = cellNum;
    652                 psFree(cellName);
    653             } else {
    654                 // We have already dealt with the case PHU=FPA, in a special case above, so if we get here
    655                 // it's an error.
    656                 psError(PS_ERR_IO, true, "PHU is not FPA, CHIP or CELL.\n");
    657                 psFree(phdu);
    658                 psFree(view);
    659                 return NULL;
    660             }
    661             psFree(chipName);
    662         }
    663 
    664         if (install) {
    665             const char *content = getContent(fileInfo, contents, chip, cell); // chip:cell:cellType triples
    666             if (!content || strlen(content) == 0) {
    667                 psError(PS_ERR_IO, false, "Unable to get CONTENTS.\n");
    668                 psFree(phdu);
    669                 psFree(view);
    670                 return NULL;
    671             }
    672             if (processContents(fpa, chip, cell, phdu, level, content, format) < 0) {
    673                 psError(PS_ERR_IO, false, "Error setting CONTENTS");
    674                 psFree(phdu);
    675                 psFree(view);
    676                 return NULL;
    677             }
    678         }
    679         psFree(phdu);
    680 
    681         if (install && header && !pmConceptsRead(fpa, chip, cell, PM_CONCEPT_SOURCE_PHU, NULL)) {
    682             psWarning("Unable to read concepts from PHU.\n");
    683         }
    684         return view;
    685     }
    686 
    687     // Case 3: EXTENSIONS=CHIP or EXTENSIONS=CELL.  We have extensions that we iterate through.  The CONTENTS
    688     // is a list of extensions.
    689     phdu->blankPHU = true;
    690     pmChip *chip = NULL;                // The chip of interest
    691     pmCell *cell = NULL;                // The cell of interest
    692 
    693     // First, put in the PHU
    694     if (strcasecmp(phuType, "FPA") == 0) {
    695         addHDUtoFPA(fpa, phdu);
    696     } else {
    697         // Get the chip
    698         psString chipName = phuNameFromHeader("CHIP.NAME", fileInfo, header); // Name of the chip
    699         int chipNum = pmFPAFindChip(fpa, chipName); // Chip number
    700         if (chipNum == -1) {
    701             psError(PS_ERR_IO, true, "Unable to find chip %s in FPA.\n", chipName);
    702             psFree(view);
    703             return NULL;
    704         }
    705         chip = fpa->chips->data[chipNum]; // The specified chip
    706         view->chip = chipNum;
    707 
    708         if (strcasecmp(phuType, "CHIP") == 0) {
    709             addHDUtoChip(chip, phdu);
    710         } else if (strcasecmp(phuType, "CELL") == 0) {
    711             psString cellName = phuNameFromHeader("CELL.NAME", fileInfo, header); // Name of the cell
    712             int cellNum = pmChipFindCell(chip, cellName); // Cell number
    713             if (cellNum == -1) {
    714                 psError(PS_ERR_IO, true, "Unable to find cell %s in chip %s.\n", cellName, chipName);
    715                 psFree(view);
    716                 return NULL;
    717             }
    718             cell = chip->cells->data[cellNum]; // The specified cell
    719             view->cell = cellNum;
    720             psFree(cellName);
    721 
    722             addHDUtoCell(cell, phdu);
    723         } else {
    724             psError(PS_ERR_IO, true, "The format of the PHU (%s) is not FPA, CHIP or CELL.\n", phuType);
    725             psFree(view);
    726             return NULL;
    727         }
    728         psFree(chipName);
    729     }
    730     psFree(phdu);
    731 
    732     pmFPALevel level = hduLevel(format);// The level at which to plug in HDU
    733 
    734     // Now go through the contents
    735     psMetadataIterator *contentsIter = psMetadataIteratorAlloc(contents, PS_LIST_HEAD, NULL);
    736     psMetadataItem *contentsItem = NULL; // Item from contents
    737     while ((contentsItem = psMetadataGetAndIncrement(contentsIter))) {
    738         const char *extName = contentsItem->name;
    739         if (contentsItem->type != PS_DATA_STRING) {
    740             psLogMsg(__func__, PS_LOG_WARN, "CONTENTS item %s is not of type STR --- ignored.\n", extName);
     1123    return NULL;
     1124}
     1125
     1126//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     1127// Public functions
     1128//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     1129
     1130pmFPA *pmFPAConstruct(const psMetadata *camera)
     1131{
     1132    PS_ASSERT_PTR_NON_NULL(camera, NULL);
     1133
     1134    pmFPA *fpa = pmFPAAlloc(camera);    // The FPA to fill out
     1135
     1136    bool mdok = true;                   // Status from MD lookups
     1137    psMetadata *components = psMetadataLookupMetadata(&mdok, camera, "FPA"); // FPA components
     1138    if (!mdok || !components) {
     1139        psError(PS_ERR_IO, true, "Failed to lookup \"FPA\"");
     1140        psFree(fpa);
     1141        return NULL;
     1142    }
     1143    psMetadataIterator *componentsIter = psMetadataIteratorAlloc(components, PS_LIST_HEAD, NULL);
     1144    psMetadataItem *componentsItem = NULL; // Item from components
     1145    while ((componentsItem = psMetadataGetAndIncrement(componentsIter))) {
     1146        const char *chipName = componentsItem->name; // Name of the chip
     1147        if (componentsItem->type != PS_DATA_STRING) {
     1148            psLogMsg(__func__, PS_LOG_WARN, "Element %s in FPA within the camera configuration is not of "
     1149                     "type STR (type=%x) --- ignored.\n", chipName, componentsItem->type);
    7411150            continue;
    7421151        }
    7431152
    744         if (install) {
    745             pmHDU *hdu = pmHDUAlloc(extName); // The extension
    746             // Casting to avoid "warning: passing arg 1 of `p_psMemIncrRefCounter' discards qualifiers from
    747             // pointer target type"
    748             hdu->format = psMemIncrRefCounter((const psPtr)format);
    749 
    750             if (processContents(fpa, chip, cell, hdu, level, contentsItem->data.V, format) < 0) {
    751                 psError(PS_ERR_IO, false, "Error setting CONTENTS");
    752                 psFree(view);
    753                 psFree(hdu);
    754                 psFree(contentsIter);
    755                 return NULL;
    756             }
    757             psFree(hdu);
    758         }
    759     }
    760     psFree(contentsIter);
    761 
    762     if (install) {
    763         if (!pmConceptsReadFPA(fpa, PM_CONCEPT_SOURCE_DEFAULTS, true, NULL)) {
    764             psWarning("Unable to read concepts from defaults for FPA.  Attempting to "
    765                       "proceed anyway.\n");
    766         }
    767 
    768         if (header && !pmConceptsRead(fpa, chip, cell, PM_CONCEPT_SOURCE_PHU, NULL)) {
    769             psWarning("Unable to read concepts from PHU.\n");
    770         }
    771     }
    772 
    773     return view;
    774 }
    775 
     1153        pmChip *chip = pmChipAlloc(fpa, chipName); // The chip
     1154        psList *cellNames = psStringSplit(componentsItem->data.V, " ,;", true); // List of cell names
     1155        psListIterator *cellNamesIter = psListIteratorAlloc(cellNames, PS_LIST_HEAD, false); // Iterator
     1156
     1157        psString cellName = NULL;       // Name of cell
     1158        while ((cellName = psListGetAndIncrement(cellNamesIter))) {
     1159            pmCell *cell = pmCellAlloc(chip, cellName); // New cell
     1160            psFree(cell);               // Drop reference
     1161        }
     1162        psFree(chip);                   // Drop reference
     1163        psFree(cellNamesIter);
     1164        psFree(cellNames);
     1165    }
     1166    psFree(componentsIter);
     1167
     1168    return fpa;
     1169}
    7761170
    7771171bool pmFPAAddSourceFromView(pmFPA *fpa, const char *fpaname, const pmFPAview *phuView,
  • trunk/psModules/src/camera/pmFPACopy.c

    r11871 r12564  
    303303    pmHDU *targetHDU = pmHDUFromCell(target); // The target HDU
    304304    if (targetHDU) {
    305         if (!targetHDU->header) {
    306             targetHDU->header = psMetadataAlloc();
    307         }
    308305        pmHDU *sourceHDU = pmHDUFromCell(source); // The source HDU
    309         if (sourceHDU->header) {
     306        if (!sourceHDU) {
     307            psWarning("Unable to copy header: no source header.");
     308        } else if (sourceHDU->header) {
    310309            targetHDU->header = psMetadataCopy(targetHDU->header, sourceHDU->header);
    311310        }
     
    315314    pmHDU *targetPHU = findBlankPHU(target); // The target PHU
    316315    if (targetPHU && targetPHU != targetHDU) {
    317         if (!targetPHU->header) {
    318             targetPHU->header = psMetadataAlloc();
    319         }
    320316//        pmHDU *sourcePHU = pmHDUGetHighest(source->parent->parent, source->parent, source); // A source HDU
    321317        pmHDU *sourcePHU = findBlankPHU(source); // The target PHU
  • trunk/psModules/src/camera/pmFPALevel.c

    r11687 r12564  
    1717const char *pmFPALevelToName(pmFPALevel level)
    1818{
    19 
    2019    switch (level) {
    2120    case PM_FPA_LEVEL_NONE:
     
    4948    } else if (!strcasecmp(name, "READOUT")) {
    5049        val = PM_FPA_LEVEL_READOUT;
     50    } else if (!strcasecmp(name, "NONE")) {
     51        val = PM_FPA_LEVEL_NONE;
    5152    } else {
     53        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unrecognised FPA level name: %s", name);
    5254        val = PM_FPA_LEVEL_NONE;
    5355    }
  • trunk/psModules/src/camera/pmFPARead.c

    r11793 r12564  
    3939                         const psRegion *trimsec, // Trim section
    4040                         const psList *biassecs, // Bias sections
    41                         fpaReadType type
     41                        fpaReadType type
    4242                        )
    4343{
     
    6565    switch (type) {
    6666      case FPA_READ_TYPE_IMAGE:
    67         if (readout->image) {
    68             psFree (readout->image);
    69         }
    70         readout->image = psMemIncrRefCounter(psImageSubset(image, region));     
    71         break;
     67        if (readout->image) {
     68            psFree (readout->image);
     69        }
     70        readout->image = psMemIncrRefCounter(psImageSubset(image, region));
     71        break;
    7272      case FPA_READ_TYPE_MASK:
    73         if (readout->mask) {
    74             psFree (readout->mask);
    75         }
    76         readout->mask = psMemIncrRefCounter(psImageSubset(image, region));     
    77         break;
     73        if (readout->mask) {
     74            psFree (readout->mask);
     75        }
     76        readout->mask = psMemIncrRefCounter(psImageSubset(image, region));
     77        break;
    7878      case FPA_READ_TYPE_WEIGHT:
    79         if (readout->weight) {
    80             psFree (readout->weight);
    81         }
    82         readout->weight = psMemIncrRefCounter(psImageSubset(image, region));   
    83         break;
     79        if (readout->weight) {
     80            psFree (readout->weight);
     81        }
     82        readout->weight = psMemIncrRefCounter(psImageSubset(image, region));
     83        break;
    8484      default:
    85         psAbort("Unknown read type: %x\n", type);
    86     }
    87    
     85        psAbort("Unknown read type: %x\n", type);
     86    }
     87
    8888    // Get the list of overscans
    8989    // XXX should this step only be performed for IMAGE, not MASK and WEIGHT types?
     
    210210    // check if we have read the desired data, read it if needed
    211211    bool (*hduReadFunc)(pmHDU*, psFits*) = NULL; // Function to use to read the HDU
    212     void *dataPointer = NULL;           // pointer to location of desired data
     212    void *dataPointer = NULL;           // pointer to location of desired data
    213213    switch (type) {
    214214      case FPA_READ_TYPE_IMAGE:
     
    234234    // do we have the data we want (image, header, or etc).
    235235    if (!dataPointer) {
    236         // attempt to read in the desired data
    237         if (!hduReadFunc(hdu, fits)) {
    238             psError(PS_ERR_UNKNOWN, false, "Unable to read HDU for cell.\n");
    239             return false;
    240         }
     236        // attempt to read in the desired data
     237        if (!hduReadFunc(hdu, fits)) {
     238            psError(PS_ERR_UNKNOWN, false, "Unable to read HDU for cell.\n");
     239            return false;
     240        }
    241241    }
    242242
     
    250250    // skip the image arrays completely for the header-only files
    251251    if (type == FPA_READ_TYPE_HEADER) {
    252         pmCellSetDataStatus(cell, true);
    253         return true;
     252        pmCellSetDataStatus(cell, true);
     253        return true;
    254254    }
    255255
    256256    // set up pointers for the different possible image arrays
    257     psArray *imageArray = NULL; // Array of images in the HDU
     257    psArray *imageArray = NULL; // Array of images in the HDU
    258258    psElemType imageType = PS_TYPE_F32; // Expected type for image
    259259    switch (type) {
     
    263263        break;
    264264      case FPA_READ_TYPE_MASK:
    265         imageArray = hdu->masks;
     265        imageArray = hdu->masks;
    266266        imageType = PS_TYPE_MASK;
    267267        break;
  • trunk/psModules/src/concepts/pmConceptsWrite.c

    r12397 r12564  
    5757        while ((cItem = psListGetAndIncrement(cIter))) {
    5858            if (cItem->type != PS_DATA_STRING) {
    59                 psLogMsg(__func__, PS_LOG_WARN, "psMetadataItem from list is of type %x instead of "
     59                psWarning("psMetadataItem from list is of type %x instead of "
    6060                         "%x (PS_DATA_STRING) --- can't interpret.\n", cItem->type, PS_DATA_STRING);
    6161                psFree(cIter);
     
    178178        }
    179179    default:
    180         psLogMsg(__func__, PS_LOG_WARN, "Type of %s is not suitable for a FITS header --- not added.\n",
     180        psWarning("Type of %s is not suitable for a FITS header --- not added.\n",
    181181                 item->name);
    182182        return false;
     
    261261                if (strcasecmp(source, "HEADER") == 0) {
    262262                    if (cameraItem->type != PS_DATA_STRING) {
    263                         psLogMsg(__func__, PS_LOG_WARN, "Concept %s is specified by header, but is not "
     263                        psWarning("Concept %s is specified by header, but is not "
    264264                                 "of type STR --- ignored.\n", conceptItem->name);
    265265                        continue;
     
    286286                    psTrace("psModules.concepts", 8, "Checking %s against camera format.\n", name);
    287287                    if (! compareConcepts(formatted, cameraItem)) {
    288                         psLogMsg(__func__, PS_LOG_WARN, "Concept %s is specified by value in the camera "
     288                        psWarning("Concept %s is specified by value in the camera "
    289289                                 "format, but the values don't match.\n", name);
    290290                    }
    291291                    psFree(formatted);
    292292                } else {
    293                     psLogMsg(__func__, PS_LOG_WARN, "Concept source %s isn't HEADER or VALUE --- can't "
     293                    psWarning("Concept source %s isn't HEADER or VALUE --- can't "
    294294                             "write\n", nameSource);
    295295                }
     
    303303
    304304                if (! compareConcepts(formatted, cameraItem)) {
    305                     psLogMsg(__func__, PS_LOG_WARN, "Concept %s is specified by value in the camera "
     305                    psWarning("Concept %s is specified by value in the camera "
    306306                             "format, but the values don't match.\n", name);
    307307                }
     
    347347                psString dependKey = psMetadataLookupStr(&mdok, defaults, dependName); // The keyword
    348348                if (!mdok || !dependKey || strlen(dependKey) == 0) {
    349                     psLogMsg(__func__, PS_LOG_WARN, "Can't find %s in the DEFAULTS for %s --- ignored.\n",
     349                    psWarning("Can't find %s in the DEFAULTS for %s --- ignored.\n",
    350350                             dependName, name);
    351351                    psFree(dependName);
     
    354354                psString dependValue = psMetadataLookupStr(&mdok, concepts, dependKey); // The value
    355355                if (!mdok || !dependValue || strlen(dependValue) == 0) {
    356                     psLogMsg(__func__, PS_LOG_WARN, "Concept %s specified by %s isn't of type STR -- "
     356                    psWarning("Concept %s specified by %s isn't of type STR -- "
    357357                             "ignored.\n", dependKey, dependName);
    358358                    psFree(dependName);
     
    360360                }
    361361                // Get the actual item of interest, and correct the name to match the concept name
    362                 defaultItem = psMetadataLookup(defaultItem->data.md, dependValue);
    363                 if (!defaultItem) {
    364                     psLogMsg(__func__, PS_LOG_WARN, "Concept dependency name %s is not found "
    365                              "in concept table for %s -- ignored.\n", dependValue, dependName);
     362                defaultItem = psMetadataLookup(defaultItem->data.md, dependValue);
     363                if (!defaultItem) {
     364                    psWarning("Concept dependency name %s is not found "
     365                             "in concept table for %s -- ignored.\n", dependValue, dependName);
    366366                    psFree(dependName);
    367367                    continue;
    368                 }
     368                }
    369369                defaultItem = psMetadataItemCopy(defaultItem);
    370370                psFree(dependName);
     
    381381            }
    382382            if (! compareConcepts(formatted, defaultItem)) {
    383                 psLogMsg(__func__, PS_LOG_WARN, "Concept %s is specified by the DEFAULTS in the camera "
     383                psWarning("Concept %s is specified by the DEFAULTS in the camera "
    384384                         "format, but the values don't match.\n", name);
    385385            }
     
    418418        if (headerItem) {
    419419            if (headerItem->type != PS_DATA_STRING) {
    420                 psLogMsg(__func__, PS_LOG_WARN, "TRANSLATION keyword for concept %s isn't of type STR ---"
     420                psWarning("TRANSLATION keyword for concept %s isn't of type STR ---"
    421421                         " ignored.", name);
    422422                continue;
     
    471471        if (dbItem) {
    472472            if (dbItem->type != PS_DATA_METADATA) {
    473                 psLogMsg(__func__, PS_LOG_WARN, "DATABASE keyword for concept %s isn't of type METADATA "
     473                psWarning("DATABASE keyword for concept %s isn't of type METADATA "
    474474                         "--- ignored.\n", name);
    475475                continue;
     
    508508                        char *dependName = psListGetAndIncrement(valuesIter); // Name for the value
    509509                        if (!strlen(column) || !strlen(name)) {
    510                             psLogMsg(__func__, PS_LOG_WARN, "One of the columns or value names for %s is "
     510                            psWarning("One of the columns or value names for %s is "
    511511                                     " empty --- ignored.\n", name);
    512512                        } else {
     
    543543                    // Note that we use limit=2 in order to test if there are multiple rows returned
    544544                    if (! dbResult || dbResult->n == 0) {
    545                         psLogMsg(__func__, PS_LOG_WARN, "Unable to find any rows in DB for %s --- "
     545                        psWarning("Unable to find any rows in DB for %s --- "
    546546                                 "ignored\n", name);
    547547                        return false;
    548548                    } else {
    549549                        if (dbResult->n > 1) {
    550                             psLogMsg(__func__, PS_LOG_WARN, "Multiple rows returned in DB lookup for %s "
     550                            psWarning("Multiple rows returned in DB lookup for %s "
    551551                                     "--- ignored.\n", name);
    552552                        }
  • trunk/psModules/src/config/pmConfig.c

    r12544 r12564  
    44 *  @author EAM (IfA)
    55 *
    6  *  @version $Revision: 1.80 $ $Name: not supported by cvs2svn $
    7  *  @date $Date: 2007-03-22 18:07:18 $
     6 *  @version $Revision: 1.81 $ $Name: not supported by cvs2svn $
     7 *  @date $Date: 2007-03-23 03:09:53 $
    88 *
    99 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    129129void pmConfigSet(const char *path)
    130130{
     131    PS_ASSERT_STRING_NON_EMPTY(path,);
     132
    131133    pmConfigDone();
    132134
  • trunk/psModules/src/config/pmConfigCamera.c

    r11754 r12564  
    1111
    1212#include "pmConfigCamera.h"
     13
     14
     15#define TABLE_OF_CONTENTS "CONTENTS"    // Name for camera format metadata containing the contents
     16#define CHIP_TYPES "CHIPS"              // Name for camera format metadata containing the chip types
     17#define CELL_TYPES "CELLS"              // Name for camera format metadata containing the cell types
    1318
    1419
     
    6873                             psMetadata *newCameras, // New list of camera configurations
    6974                             const char *name, // Name of original camera configuration
    70                              pmFPALevel level // Level
     75                             pmFPALevel mosaicLevel // Level to which we are mosaicking
    7176                            )
    7277{
     
    7479    assert(newCameras);
    7580    assert(name);
    76     assert(level == PM_FPA_LEVEL_CHIP || level == PM_FPA_LEVEL_FPA);
     81    assert(mosaicLevel == PM_FPA_LEVEL_CHIP || mosaicLevel == PM_FPA_LEVEL_FPA);
    7782
    7883    // See if the old one is there
     
    8489    // See if the new one is already there
    8590    psString newName = NULL;       // Name of mosaicked camera
    86     psStringAppend(&newName, "_%s-%s", name, level == PM_FPA_LEVEL_CHIP ? "CHIP" : "FPA");
     91    psStringAppend(&newName, "_%s-%s", name, mosaicLevel == PM_FPA_LEVEL_CHIP ? "CHIP" : "FPA");
    8792    if (psMetadataLookup(oldCameras, newName)) {
    8893        return true;
     
    99104        return NULL;
    100105    }
    101     switch (level) {
    102     case PM_FPA_LEVEL_CHIP: {
    103             // Replace the contents of each chip with a single cell
    104             psMetadataIterator *fpaIter = psMetadataIteratorAlloc(fpa, PS_LIST_HEAD, NULL); // Iterator
    105             psMetadataItem *fpaItem = NULL;     // Item from iteration
    106             while ((fpaItem = psMetadataGetAndIncrement(fpaIter))) {
    107                 if (fpaItem->type != PS_DATA_STRING) {
    108                     psWarning("Element %s within FPA in camera configuration is not of type STR.",
    109                               fpaItem->name);
    110                     continue;
    111                 }
    112 
    113                 psFree(fpaItem->data.str);
    114                 fpaItem->data.str = psStringCopy("MosaickedCell");
    115                 psFree(fpaItem->comment);
    116                 fpaItem->comment = psStringCopy("Mosaicked cell; automatically generated");
    117             }
    118             psFree(fpaIter);
    119         }
    120         break;
    121     case PM_FPA_LEVEL_FPA: {
    122             while (psListLength(fpa->list) > 0) {
    123                 psMetadataRemoveIndex(fpa, PS_LIST_TAIL);
    124             }
    125 
    126             psMetadataAddStr(fpa, PS_LIST_HEAD, "MosaickedChip", 0,
    127                              "Mosaicked chip with mosaicked cell; automatically generated",
    128                              "MosaickedCell");
    129         }
    130         break;
     106    switch (mosaicLevel) {
     107      case PM_FPA_LEVEL_CHIP: {
     108          // Replace the contents of each chip with a single cell
     109          psMetadataIterator *fpaIter = psMetadataIteratorAlloc(fpa, PS_LIST_HEAD, NULL); // Iterator
     110          psMetadataItem *fpaItem = NULL;     // Item from iteration
     111          while ((fpaItem = psMetadataGetAndIncrement(fpaIter))) {
     112              if (fpaItem->type != PS_DATA_STRING) {
     113                  psWarning("Element %s within FPA in camera configuration is not of type STR.",
     114                            fpaItem->name);
     115                  continue;
     116              }
     117
     118              psFree(fpaItem->data.str);
     119              fpaItem->data.str = psStringCopy("MosaickedCell");
     120              psFree(fpaItem->comment);
     121              fpaItem->comment = psStringCopy("Mosaicked cell; automatically generated");
     122          }
     123          psFree(fpaIter);
     124          break;
     125      }
     126      case PM_FPA_LEVEL_FPA: {
     127          // Replace the contents of the FPA with a single chip containing a single cell
     128          while (psListLength(fpa->list) > 0) {
     129              psMetadataRemoveIndex(fpa, PS_LIST_TAIL);
     130          }
     131
     132          psMetadataAddStr(fpa, PS_LIST_HEAD, "MosaickedChip", 0,
     133                           "Mosaicked chip with mosaicked cell; automatically generated",
     134                           "MosaickedCell");
     135          break;
     136      }
    131137    default:
    132138        psAbort("Should never get here.\n");
     
    142148        psMetadata *format = formatsItem->data.V; // The camera format
    143149
    144         // Add a RULE
     150        // Add a RULE, so that when a mosaic is written to a FITS file, it can be recognised again when read.
    145151        psMetadata *rule = psMetadataLookupMetadata(&mdok, format, "RULE"); // Way to identify format from PHU
    146152        if (!mdok || !rule) {
     
    148154            continue;
    149155        }
    150         switch (level) {
     156        switch (mosaicLevel) {
    151157        case PM_FPA_LEVEL_CHIP:
    152158            psMetadataAddStr(rule, PS_LIST_TAIL, "PSMOSAIC", 0, "Mosaicked level", "CHIP");
     
    173179        }
    174180        if (strcasecmp(phuItem->data.str, "CELL") == 0 ||
    175                 (level == PM_FPA_LEVEL_FPA && (strcasecmp(phuItem->data.str, "CHIP") == 0))) {
     181                (mosaicLevel == PM_FPA_LEVEL_FPA && (strcasecmp(phuItem->data.str, "CHIP") == 0))) {
    176182            psFree(phuItem->data.str);
    177             if (level == PM_FPA_LEVEL_CHIP) {
     183            if (mosaicLevel == PM_FPA_LEVEL_CHIP) {
    178184                phuItem->data.str = psStringCopy("CHIP");
    179185            } else {
     
    187193            continue;
    188194        }
    189         switch (level) {
    190         case PM_FPA_LEVEL_CHIP:
    191             if (strcasecmp(extensionsItem->data.str, "NONE") == 0) {
    192                 if (strcasecmp(phuItem->data.str, "FPA") == 0) {
    193                     break;              // Don't need a "CONTENT" to identify the content!
    194                 }
    195                 psMetadataItem *contentItem = psMetadataLookup(file, "CONTENT"); // Key to CONTENTS menu
    196                 if (!contentItem || contentItem->type != PS_DATA_STRING) {
    197                     psWarning("Couldn't find CONTENT of type STR in the FILE information "
    198                               "in the camera format %s.\n", formatsItem->name);
    199                     continue;
    200                 }
    201                 psFree(contentItem->data.str);
    202                 contentItem->data.str = psStringCopy("{CHIP.NAME}");
    203             } else if (strcasecmp(extensionsItem->data.str, "CELL") == 0) {
     195        switch (mosaicLevel) {
     196          case PM_FPA_LEVEL_CHIP:
     197            if (strcasecmp(phuItem->data.str, "FPA") == 0 &&
     198                strcasecmp(extensionsItem->data.str, "CELL") == 0) {
    204199                psFree(extensionsItem->data.str);
    205200                extensionsItem->data.str = psStringCopy("CHIP");
    206             }
    207             break;
    208         case PM_FPA_LEVEL_FPA:
     201            } else {
     202                psFree(extensionsItem->data.str);
     203                extensionsItem->data.str = psStringCopy("NONE");
     204
     205                if (strcasecmp(phuItem->data.str, "FPA") == 0) {
     206                    // Don't need a "CONTENT" to identify the content!
     207                    if (psMetadataLookup(file, "CONTENT")) {
     208                        psMetadataRemoveKey(file, "CONTENT");
     209                    }
     210                    break;
     211                }
     212                psMetadataAddStr(file, PS_LIST_TAIL, "CONTENT", PS_META_REPLACE, "Key to CONTENTS menu",
     213                                 "{CHIP.NAME}");
     214            }
     215
     216#if 0
     217            // Don't need CELL.NAME for chip-mosaicked camera
     218            if (psMetadataLookup(file, "CELL.NAME")) {
     219                psMetadataRemoveKey(file, "CELL.NAME");
     220            }
     221#endif
     222            break;
     223          case PM_FPA_LEVEL_FPA:
    209224            psFree(extensionsItem->data.str);
    210225            extensionsItem->data.str = psStringCopy("NONE");
     226#if 0
     227            // Don't need CHIP.NAME or CELL.NAME for fpa-mosaicked camera
     228            if (psMetadataLookup(file, "CHIP.NAME")) {
     229                psMetadataRemoveKey(file, "CHIP.NAME");
     230            }
     231            if (psMetadataLookup(file, "CELL.NAME")) {
     232                psMetadataRemoveKey(file, "CELL.NAME");
     233            }
     234#endif
    211235            break;
    212236        default:
     
    215239
    216240        // Fix up the CONTENTS to contain only the mosaicked cell for each chip
    217         switch (level) {
    218         case PM_FPA_LEVEL_CHIP:
    219             if (strcasecmp(phuItem->data.str, "FPA") == 0 &&
    220                     strcasecmp(extensionsItem->data.str, "NONE") == 0) {
    221                 // List the contents on a single line
    222                 psString contentsLine = NULL; // Contents of the PHU
    223                 psMetadataIterator *fpaIter = psMetadataIteratorAlloc(fpa, PS_LIST_HEAD, NULL); // Iterator
    224                 psMetadataItem *fpaItem;    // Item from iteration
    225                 while ((fpaItem = psMetadataGetAndIncrement(fpaIter))) {
    226                     if (fpaItem->type != PS_DATA_STRING) {
    227                         // We've already thrown a warning on this, above.
    228                         continue;
     241        switch (mosaicLevel) {
     242          case PM_FPA_LEVEL_FPA:
     243            psMetadataAddStr(format, PS_LIST_TAIL, TABLE_OF_CONTENTS, PS_META_REPLACE, NULL,
     244                             "MosaickedChip:MosaickedCell:_mosaic");
     245            break;
     246          case PM_FPA_LEVEL_CHIP:
     247            if (strcasecmp(phuItem->data.str, "FPA") == 0) {
     248                if (strcasecmp(extensionsItem->data.str, "CHIP") == 0) {
     249                    // List the chipName:chipType for each chip.
     250
     251                    psMetadata *contents = psMetadataAlloc(); // List of contents, with chipName:chipType
     252
     253                    psMetadataIterator *fpaIter = psMetadataIteratorAlloc(fpa, PS_LIST_HEAD, NULL); // Iteratr
     254                    psMetadataItem *fpaItem;    // Item from iteration
     255                    while ((fpaItem = psMetadataGetAndIncrement(fpaIter))) {
     256                        if (fpaItem->type != PS_DATA_STRING) {
     257                            // We've already thrown a warning on this, above.
     258                            continue;
     259                        }
     260                        psString content = NULL; // Content to add
     261                        psStringAppend(&content, "%s:_mosaicChip ", fpaItem->name);
     262                        psMetadataAddStr(contents, PS_LIST_TAIL, fpaItem->name, 0, NULL, content);
     263                        psFree(content);
    229264                    }
    230                     psStringAppend(&contentsLine, "%s:MosaickedCell:_mosaic ", fpaItem->name);
     265                    psFree(fpaIter);
     266                    psMetadataAddMetadata(format, PS_LIST_TAIL, TABLE_OF_CONTENTS, PS_META_REPLACE,
     267                                          "List of contents", contents);
     268                    psFree(contents);
     269
     270                    psMetadata *chips = psMetadataAlloc(); // List of chip types, with cellName:cellType
     271                    psMetadataAddStr(chips, PS_LIST_TAIL, "_mosaicChip", 0, NULL,
     272                                     "MosaickedCell:_mosaic");
     273                    psMetadataAddMetadata(format, PS_LIST_TAIL, CHIP_TYPES, PS_META_REPLACE,
     274                                          "List of chip types", chips);
     275                    psFree(chips);
     276                    break;
     277                } else if (strcasecmp(extensionsItem->data.str, "NONE") == 0) {
     278                    // List the contents on a single line
     279                    psString contentsLine = NULL; // Contents of the PHU
     280                    psMetadataIterator *fpaIter = psMetadataIteratorAlloc(fpa, PS_LIST_HEAD, NULL); // Iteratr
     281                    psMetadataItem *fpaItem;    // Item from iteration
     282                    while ((fpaItem = psMetadataGetAndIncrement(fpaIter))) {
     283                        if (fpaItem->type != PS_DATA_STRING) {
     284                            // We've already thrown a warning on this, above.
     285                            continue;
     286                        }
     287                        psStringAppend(&contentsLine, "%s:MosaickedCell:_mosaic ", fpaItem->name);
     288                    }
     289                    psFree(fpaIter);
     290                    psMetadataAddStr(format, PS_LIST_TAIL, TABLE_OF_CONTENTS, PS_META_REPLACE,
     291                                     NULL, contentsLine);
     292                    psFree(contentsLine);
     293                    break;
    231294                }
    232                 psFree(fpaIter);
    233                 psMetadataAddStr(format, PS_LIST_TAIL, "CONTENTS", PS_META_REPLACE, NULL, contentsLine);
    234                 psFree(contentsLine);
    235                 break;
    236             }
    237 
    238             psMetadata *contents = psMetadataLookupMetadata(&mdok, format, "CONTENTS"); // Contents of file
     295            }
     296            // PHU level is CHIP, EXTENSIONS is NONE.
     297
     298            psMetadata *contents = psMetadataLookupMetadata(&mdok, format,
     299                                                            TABLE_OF_CONTENTS); // File contents
    239300            if (!mdok || !contents) {
    240                 psWarning("Couldn't find CONTENTS in the camera format %s.\n", formatsItem->name);
     301                psWarning("Couldn't find %s in the camera format %s.\n", TABLE_OF_CONTENTS,
     302                          formatsItem->name);
    241303                continue;
    242304            }
     
    244306                psMetadataRemoveIndex(contents, PS_LIST_TAIL);
    245307            }
     308
    246309            psMetadataIterator *fpaIter = psMetadataIteratorAlloc(fpa, PS_LIST_HEAD, NULL); // Iterator
    247310            psMetadataItem *fpaItem;    // Item from iteration
     
    252315                }
    253316
    254                 psString content = NULL;    // Content of the chip
    255                 psStringAppend(&content, "%s:MosaickedCell:_mosaic", fpaItem->name);
    256                 psMetadataAddStr(contents, PS_LIST_TAIL, fpaItem->name, 0, NULL, content);
    257                 psFree(content);            // Drop reference
     317                psMetadataAddStr(contents, PS_LIST_TAIL, fpaItem->name, 0, NULL, "_mosaicChip");
    258318            }
    259319            psFree(fpaIter);
    260             break;
    261         case PM_FPA_LEVEL_FPA:
    262             psMetadataAddStr(format, PS_LIST_TAIL, "CONTENTS", PS_META_REPLACE, NULL,
    263                              "MosaickedChip:MosaickedCell:_mosaic");
     320
     321            psMetadata *chips = psMetadataAlloc(); // List of chip types, with cellName:cellType
     322            psMetadataAddStr(chips, PS_LIST_TAIL, "_mosaicChip", 0, NULL,
     323                             "MosaickedCell:_mosaic");
     324            psMetadataAddMetadata(format, PS_LIST_TAIL, CHIP_TYPES, PS_META_REPLACE,
     325                                  "List of chip types", chips);
     326            psFree(chips);
    264327            break;
    265328        default:
     
    268331
    269332        // Fix the cell type
    270         psMetadata *cells = psMetadataLookupMetadata(&mdok, format, "CELLS"); // CELLS information
     333        psMetadata *cells = psMetadataLookupMetadata(&mdok, format, CELL_TYPES); // CELLS information
    271334        if (!mdok || !cells) {
    272335            psWarning("Couldn't find CELLS of type METADATA in the camera format %s.\n", formatsItem->name);
     
    316379        }
    317380
    318         if (level == PM_FPA_LEVEL_FPA) {
     381        if (mosaicLevel == PM_FPA_LEVEL_FPA) {
    319382            removeChipConceptsSources(translation);
    320383            removeChipConceptsSources(database);
     
    347410}
    348411
    349 
    350412// Generate the chip mosaicked version of a camera configuration
    351413bool pmConfigCameraMosaickedVersions(psMetadata *site, // The site configuration
Note: See TracChangeset for help on using the changeset viewer.