IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

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.

File:
1 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,
Note: See TracChangeset for help on using the changeset viewer.