Changeset 6570
- Timestamp:
- Mar 10, 2006, 5:20:10 PM (20 years ago)
- Location:
- branches/rel10_ifa/psModules/src/astrom
- Files:
-
- 6 edited
-
pmConcepts.c (modified) (29 diffs)
-
pmConcepts.h (modified) (7 diffs)
-
pmConceptsRead.c (modified) (2 diffs)
-
pmConceptsStandard.c (modified) (8 diffs)
-
pmConceptsStandard.h (modified) (1 diff)
-
pmConceptsWrite.c (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/rel10_ifa/psModules/src/astrom/pmConcepts.c
r6552 r6570 23 23 24 24 pmConceptSpec *pmConceptSpecAlloc(psMetadataItem *blank, // Blank value; contains the name 25 pmConcept ReadFunc read, // Function to call to readthe concept26 pmConcept WriteFunc write // Function to call to writethe concept25 pmConceptParseFunc parse, // Function to call to parse the concept 26 pmConceptFormatFunc format // Function to call to format the concept 27 27 ) 28 28 { … … 31 31 32 32 spec->blank = psMemIncrRefCounter(blank); 33 spec-> read = read;34 spec-> write = write;33 spec->parse = parse; 34 spec->format = format; 35 35 36 36 return spec; … … 39 39 40 40 bool pmConceptRegister(psMetadataItem *blank, // Blank value; contains the name 41 pmConcept ReadFunc read, // Function to call to readthe concept42 pmConcept WriteFunc write, // Function to call to writethe concept41 pmConceptParseFunc parse, // Function to call to parse the concept 42 pmConceptFormatFunc format, // Function to call to format the concept 43 43 pmConceptLevel level // Level at which to store concept in the FPA hierarchy 44 44 ) … … 49 49 } 50 50 51 pmConceptSpec *spec = pmConceptSpecAlloc(blank, read, write); // The concept specification51 pmConceptSpec *spec = pmConceptSpecAlloc(blank, parse, format); // The concept specification 52 52 psMetadata **target = NULL; // The metadata of known concepts to write to 53 53 switch (level) { … … 74 74 } 75 75 76 // This function gets called for the really boring concepts --- where all you have to do is read from a header77 // or database and you don't need to muck around with conversions.78 // There is no similar "writePlain", since the type is already known.79 static psMetadataItem *readPlain(psMetadataItem *blank, // The blank value with name, comment, type80 pmFPA *fpa, // The FPA of interest81 pmChip *chip, // The Chip of interest82 pmCell *cell, // The cell of interest83 psDB *db // Database handle84 )85 {86 switch (blank->type) {87 case PS_DATA_STRING: {88 psString string = pmConceptReadString(fpa, chip, cell, db, blank->name);89 psMetadataItem *item = psMetadataItemAllocStr(blank->name, blank->comment, string);90 psFree(string);91 return item;92 }93 case PS_DATA_S32:94 return psMetadataItemAllocS32(blank->name, blank->comment,95 pmConceptReadS32(fpa, chip, cell, db, blank->name));96 case PS_DATA_F32:97 return psMetadataItemAllocF32(blank->name, blank->comment,98 pmConceptReadF32(fpa, chip, cell, db, blank->name));99 case PS_DATA_F64:100 return psMetadataItemAllocF64(blank->name, blank->comment,101 pmConceptReadF64(fpa, chip, cell, db, blank->name));102 default:103 psLogMsg(__func__, PS_LOG_WARN, "Concept %s (%s) is not of a standard type (%x)\n",104 blank->name, blank->comment, blank->type);105 }106 return NULL;107 }108 76 109 77 // Set all registered concepts to blank value for the specified level 110 static bool conceptsBlank(psMetadata * *specs, // One of the concepts specifications78 static bool conceptsBlank(psMetadata *specs, // One of the concepts specifications 111 79 psMetadata *target // Place to install the concepts 112 80 ) … … 128 96 } 129 97 98 99 130 100 // Read all registered concepts for the specified level 131 static bool conceptsRead(psMetadata * *specs, // One of the concepts specifications101 static bool conceptsRead(psMetadata *specs, // One of the concepts specifications 132 102 pmFPA *fpa, // The FPA 133 103 pmChip *chip, // The chip 134 104 pmCell *cell, // The cell 105 pmConceptSource source, // The source of the concepts to read 135 106 psDB *db, // Database handle 136 107 psMetadata *target // Place into which to read the concepts … … 140 111 pmConceptsInit(); 141 112 } 142 psMetadataIterator *specsIter = psMetadataIteratorAlloc(*specs, PS_LIST_HEAD, NULL); // Iterator on specs 143 psMetadataItem *specItem = NULL; // Item from the specs metadata 144 while ((specItem = psMetadataGetAndIncrement(specsIter))) { 145 pmConceptSpec *spec = specItem->data.V; // The specification 146 psMetadataItem *conceptItem = NULL; // The item to add to the concepts 147 if (spec->read) { 148 conceptItem = spec->read(fpa, chip, cell, db); 149 } else { 150 conceptItem = readPlain(spec->blank, fpa, chip, cell, db); 151 if (conceptItem->type != spec->blank->type) { 152 psLogMsg(__func__, PS_LOG_ERROR, "Type of concept %s following read (%x) does not match " 153 "blank type (%x).\n", spec->blank->name, conceptItem->type, spec->blank->type); 154 } 155 } 156 if (conceptItem) { 157 psMetadataAddItem(target, conceptItem, PS_LIST_TAIL, PS_META_REPLACE); 158 psFree(conceptItem); // Drop reference 159 } 160 // No error if conceptItem is NULL, since that may only mean that the required information isn't 161 // present yet. 162 } 163 psFree(specsIter); 113 114 if (source & PM_CONCEPT_SOURCE_CAMERA || source == PM_CONCEPT_SOURCE_ALL) { 115 pmConceptsReadFromCamera(specs, cell, target); 116 } 117 if (source & PM_CONCEPT_SOURCE_DEFAULTS || source == PM_CONCEPT_SOURCE_ALL) { 118 pmConceptsReadFromDefaults(specs, fpa, chip, cell, target); 119 } 120 if (source & PM_CONCEPT_SOURCE_HEADER || source == PM_CONCEPT_SOURCE_ALL) { 121 pmConceptsReadFromHeader(specs, fpa, chip, cell, target); 122 } 123 if (source & PM_CONCEPT_SOURCE_DATABASE || source == PM_CONCEPT_SOURCE_ALL) { 124 pmConceptsReadFromHeader(specs, fpa, chip, cell, db, target); 125 } 126 164 127 return true; 165 128 } 166 129 167 130 // Write all registered concepts for the specified level 168 static bool conceptsWrite(psMetadata * *specs, // One of the concepts specifications131 static bool conceptsWrite(psMetadata *specs, // One of the concepts specifications 169 132 pmFPA *fpa, // The FPA 170 133 pmChip *chip, // The chip 171 134 pmCell *cell, // The cell 135 pmConceptSource source, // The source of the concepts to write 172 136 psDB *db, // Database handle 173 psMetadata * source// The concepts to write out137 psMetadata *concepts // The concepts to write out 174 138 ) 175 139 { … … 177 141 pmConceptsInit(); 178 142 } 179 if (! fpa->camera) { 180 return false; 181 } 182 psMetadataIterator *iter = psMetadataIteratorAlloc(source, PS_LIST_HEAD, NULL); // Iterator on concepts 183 psMetadataItem *item = NULL; // Item from the concepts 184 while ((item = psMetadataGetAndIncrement(iter))) { 185 const char *name = item->name; // Name of the concept 186 if (!strcmp(name, "CELL.NAME") || !strcmp(name, "CHIP.NAME")) { 187 // These concepts are not written out; they are set from things like the FITS extname 188 continue; 189 } 190 psMetadataItem *specItem = psMetadataLookup(*specs, name); // Specification for the concept 191 if (specItem) { 192 pmConceptSpec *spec = specItem->data.V; // The specification 193 if (spec->write) { 194 spec->write(fpa, chip, cell, db); // The concept 195 } else { 196 pmConceptWrite(fpa, chip, cell, db, source, spec->blank->name); 197 } 198 } else { 199 psLogMsg(__func__, PS_LOG_WARN, "Unable to find specification to write concept %s in FPA\n", 200 name); 201 } 202 } 203 psFree(iter); 143 144 if (source & PM_CONCEPT_SOURCE_CAMERA || source == PM_CONCEPT_SOURCE_ALL) { 145 pmConceptsWriteToCamera(specs, cell, concepts); 146 } 147 if (source & PM_CONCEPT_SOURCE_DEFAULTS || source == PM_CONCEPT_SOURCE_ALL) { 148 pmConceptsWriteToDefaults(specs, fpa, chip, cell, concepts); 149 } 150 if (source & PM_CONCEPT_SOURCE_HEADER || source == PM_CONCEPT_SOURCE_ALL) { 151 pmConceptsWriteToHeader(specs, fpa, chip, cell, concepts); 152 } 153 if (source & PM_CONCEPT_SOURCE_DATABASE || source == PM_CONCEPT_SOURCE_ALL) { 154 pmConceptsWriteToHeader(specs, fpa, chip, cell, db, concepts); 155 } 204 156 205 157 return true; 206 158 } 159 207 160 208 161 // Set the concepts for a given FPA to blanks … … 211 164 { 212 165 psTrace("psModule.concepts", 5, "Blanking FPA concepts: %x %x\n", conceptsFPA, fpa->concepts); 213 return conceptsBlank( &conceptsFPA, fpa->concepts);166 return conceptsBlank(conceptsFPA, fpa->concepts); 214 167 } 215 168 216 169 // Read the concepts for a given FPA 217 170 bool pmConceptsReadFPA(pmFPA *fpa, // FPA for which to read concepts 171 pmConceptSource source, // The source of the concepts to read 218 172 psDB *db // Database handle 219 173 ) 220 174 { 221 175 psTrace("psModule.concepts", 5, "Reading FPA concepts: %x %x\n", conceptsFPA, fpa->concepts); 222 return conceptsRead( &conceptsFPA, fpa, NULL, NULL, db, fpa->concepts);176 return conceptsRead(conceptsFPA, fpa, NULL, NULL, source, db, fpa->concepts); 223 177 } 224 178 … … 229 183 { 230 184 psTrace("psModule.concepts", 5, "Writing FPA concepts: %x %x\n", conceptsFPA, fpa->concepts); 231 return conceptsWrite( &conceptsFPA, fpa, NULL, NULL, db, fpa->concepts);185 return conceptsWrite(conceptsFPA, fpa, NULL, NULL, db, fpa->concepts); 232 186 } 233 187 … … 237 191 { 238 192 psTrace("psModule.concepts", 5, "Blanking chip concepts: %x %x\n", conceptsChip, chip->concepts); 239 return conceptsBlank( &conceptsChip, chip->concepts);193 return conceptsBlank(conceptsChip, chip->concepts); 240 194 } 241 195 242 196 // Read the concepts for a given FPA 243 197 bool pmConceptsReadChip(pmChip *chip, // Chip for which to read concepts 198 pmConceptSource source, // The source of the concepts to read 244 199 psDB *db // Database handle 245 200 ) … … 247 202 psTrace("psModule.concepts", 5, "Reading chip concepts: %x %x\n", conceptsChip, chip->concepts); 248 203 pmFPA *fpa = chip->parent; // FPA to which the chip belongs 249 return conceptsRead( &conceptsChip, fpa, chip, NULL, db, chip->concepts);204 return conceptsRead(conceptsChip, fpa, chip, NULL, source, db, chip->concepts); 250 205 } 251 206 … … 257 212 psTrace("psModule.concepts", 5, "Writing chip concepts: %x %x\n", conceptsChip, chip->concepts); 258 213 pmFPA *fpa = chip->parent; // FPA to which the chip belongs 259 return conceptsWrite( &conceptsChip, fpa, chip, NULL, db, chip->concepts);214 return conceptsWrite(conceptsChip, fpa, chip, NULL, db, chip->concepts); 260 215 } 261 216 … … 265 220 { 266 221 psTrace("psModule.concepts", 5, "Blanking cell concepts: %x %x\n", conceptsCell, cell->concepts); 267 return conceptsBlank( &conceptsCell, cell->concepts);222 return conceptsBlank(conceptsCell, cell->concepts); 268 223 } 269 224 270 225 // Read the concepts for a given FPA 271 226 bool pmConceptsReadCell(pmCell *cell, // Cell for which to read concepts 227 pmConceptSource source, // The source of the concepts to read 272 228 psDB *db // Database handle 273 229 ) … … 276 232 pmChip *chip = cell->parent; // Chip to which the cell belongs 277 233 pmFPA *fpa = chip->parent; // FPA to which the chip belongs 278 return conceptsRead( &conceptsCell, fpa, chip, cell, db, cell->concepts);234 return conceptsRead(conceptsCell, fpa, chip, cell, source, db, cell->concepts); 279 235 } 280 236 … … 287 243 pmChip *chip = cell->parent; // Chip to which the cell belongs 288 244 pmFPA *fpa = chip->parent; // FPA to which the chip belongs 289 return conceptsWrite( &conceptsCell, fpa, chip, cell, db, cell->concepts);245 return conceptsWrite(conceptsCell, fpa, chip, cell, db, cell->concepts); 290 246 } 291 247 … … 300 256 // Install the standard concepts 301 257 258 #if 0 302 259 // FPA.NAME 303 260 { … … 306 263 psFree(fpaName); 307 264 } 265 #endif 308 266 309 267 // FPA.AIRMASS … … 340 298 { 341 299 psMetadataItem *fpaRa = psMetadataItemAllocF64("FPA.RA", "Right Ascension of boresight", NAN); 342 pmConceptRegister(fpaRa, (pmConcept ReadFunc)pmConceptRead_FPA_RA,343 (pmConcept WriteFunc)pmConceptWrite_FPA_RA, PM_CONCEPT_LEVEL_FPA);300 pmConceptRegister(fpaRa, (pmConceptParseFunc)pmConceptParse_FPA_Coords, 301 (pmConceptFormatFunc)pmConceptFormat_FPA_Coords, PM_CONCEPT_LEVEL_FPA); 344 302 psFree(fpaRa); 345 303 } … … 348 306 { 349 307 psMetadataItem *fpaDec = psMetadataItemAllocF64("FPA.DEC", "Declination of boresight", NAN); 350 pmConceptRegister(fpaDec, (pmConcept ReadFunc)pmConceptRead_FPA_DEC,351 (pmConcept WriteFunc)pmConceptWrite_FPA_DEC, PM_CONCEPT_LEVEL_FPA);308 pmConceptRegister(fpaDec, (pmConceptParseFunc)pmConceptParse_FPA_Coords, 309 (pmConceptFormatFunc)pmConceptFormat_FPA_Coords, PM_CONCEPT_LEVEL_FPA); 352 310 psFree(fpaDec); 353 311 } … … 436 394 437 395 // CELL.DARKTIME 438 { 396 {Read 439 397 psMetadataItem *cellDarktime = psMetadataItemAllocF32("CELL.DARKTIME", 440 398 "Time since flush (sec)", NAN); … … 450 408 "Trim section", trimsec); 451 409 psFree(trimsec); 452 pmConceptRegister(cellTrimsec, (pmConcept ReadFunc)pmConceptRead_CELL_TRIMSEC,453 (pmConcept WriteFunc)pmConceptWrite_CELL_TRIMSEC, PM_CONCEPT_LEVEL_CELL);410 pmConceptRegister(cellTrimsec, (pmConceptParseFunc)pmConceptParse_CELL_TRIMSEC, 411 (pmConceptFormatFunc)pmConceptFormat_CELL_TRIMSEC, PM_CONCEPT_LEVEL_CELL); 454 412 psFree(cellTrimsec); 455 413 } … … 461 419 "Bias sections", biassecs); 462 420 psFree(biassecs); 463 pmConceptRegister(cellBiassec, (pmConcept ReadFunc)pmConceptRead_CELL_BIASSEC,464 (pmConcept WriteFunc)pmConceptWrite_CELL_BIASSEC, PM_CONCEPT_LEVEL_CELL);421 pmConceptRegister(cellBiassec, (pmConceptParseFunc)pmConceptParse_CELL_BIASSEC, 422 (pmConceptFormatFunc)pmConceptFormat_CELL_BIASSEC, PM_CONCEPT_LEVEL_CELL); 465 423 psFree(cellBiassec); 466 424 } … … 469 427 { 470 428 psMetadataItem *cellXbin = psMetadataItemAllocS32("CELL.XBIN", "Binning in x", 0); 471 pmConceptRegister(cellXbin, (pmConcept ReadFunc)pmConceptRead_CELL_XBIN,472 (pmConcept WriteFunc)pmConceptWrite_CELL_XBIN, PM_CONCEPT_LEVEL_CELL);429 pmConceptRegister(cellXbin, (pmConceptParseFunc)pmConceptParse_CELL_Binning, 430 (pmConceptFormatFunc)pmConceptFormat_CELL_Binning, PM_CONCEPT_LEVEL_CELL); 473 431 psFree(cellXbin); 474 432 } … … 477 435 { 478 436 psMetadataItem *cellYbin = psMetadataItemAllocS32("CELL.YBIN", "Binning in y", 0); 479 pmConceptRegister(cellYbin, (pmConcept ReadFunc)pmConceptRead_CELL_YBIN,480 (pmConcept WriteFunc)pmConceptWrite_CELL_YBIN, PM_CONCEPT_LEVEL_CELL);437 pmConceptRegister(cellYbin, (pmConceptParseFunc)pmConceptParse_CELL_Binning, 438 (pmConceptFormatFunc)pmConceptFormat_CELL_Binning, PM_CONCEPT_LEVEL_CELL); 481 439 psFree(cellYbin); 482 440 } … … 485 443 { 486 444 psMetadataItem *cellTimesys = psMetadataItemAllocS32("CELL.TIMESYS", "Time system", -1); 487 pmConceptRegister(cellTimesys, (pmConcept ReadFunc)pmConceptRead_CELL_TIMESYS,488 (pmConcept WriteFunc)pmConceptWrite_CELL_TIMESYS, PM_CONCEPT_LEVEL_CELL);445 pmConceptRegister(cellTimesys, (pmConceptParseFunc)pmConceptParse_CELL_TIMESYS, 446 (pmConceptFormatFunc)pmConceptFormat_CELL_TIMESYS, PM_CONCEPT_LEVEL_CELL); 489 447 psFree(cellTimesys); 490 448 } … … 499 457 "Time of exposure", time); 500 458 psFree(time); 501 pmConceptRegister(cellTime, (pmConcept ReadFunc)pmConceptRead_CELL_TIME,502 (pmConcept WriteFunc)pmConceptWrite_CELL_TIME, PM_CONCEPT_LEVEL_CELL);459 pmConceptRegister(cellTime, (pmConceptParseFunc)pmConceptParse_CELL_TIME, 460 (pmConceptFormatFunc)pmConceptFormat_CELL_TIME, PM_CONCEPT_LEVEL_CELL); 503 461 psFree(cellTime); 504 462 } … … 507 465 { 508 466 psMetadataItem *cellX0 = psMetadataItemAllocS32("CELL.X0", "Position of (0,0) on the chip", 0); 509 pmConceptRegister(cellX0, (pmConcept ReadFunc)pmConceptRead_CELL_X0,510 (pmConcept WriteFunc)pmConceptWrite_CELL_X0, PM_CONCEPT_LEVEL_CELL);467 pmConceptRegister(cellX0, (pmConceptParseFunc)pmConceptParse_CELL_Positions, 468 (pmConceptFormatFunc)pmConceptFormat_CELL_Positions, PM_CONCEPT_LEVEL_CELL); 511 469 psFree(cellX0); 512 470 } … … 515 473 { 516 474 psMetadataItem *cellY0 = psMetadataItemAllocS32("CELL.Y0", "Position of (0,0) on the chip", 0); 517 pmConceptRegister(cellY0, (pmConcept ReadFunc)pmConceptRead_CELL_Y0,518 (pmConcept WriteFunc)pmConceptWrite_CELL_Y0, PM_CONCEPT_LEVEL_CELL);475 pmConceptRegister(cellY0, (pmConceptParseFunc)pmConceptParse_CELL_Positions, 476 (pmConceptFormatFunc)pmConceptFormat_CELL_Positions, PM_CONCEPT_LEVEL_CELL); 519 477 psFree(cellY0); 520 478 } -
branches/rel10_ifa/psModules/src/astrom/pmConcepts.h
r6552 r6570 6 6 #include "pmFPA.h" 7 7 8 // Function to call to read a concept 9 typedef psMetadataItem* (*pmConceptReadFunc)(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 10 // Function to call to write a concept 11 typedef bool (*pmConceptWriteFunc)(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 8 9 // Function to call to parse a concept once it has been read 10 typedef psMetadataItem* (*pmConceptParseFunc)(psMetadataItem *concept, pmConceptSpec *spec, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell); 11 // Function to call to format a concept for writing 12 typedef psMetadataItem* (*pmConceptFormatFunc)(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell); 12 13 13 14 // A "concept" specification … … 15 16 { 16 17 psMetadataItem *blank; // Blank value of concept; also contains the name 17 pmConcept ReadFunc read;// Function to call to read the concept18 pmConcept WriteFunc write;// Function to call to write the concept18 pmConceptParseFunc parse; // Function to call to read the concept 19 pmConceptFormatFunc format; // Function to call to write the concept 19 20 } 20 21 pmConceptSpec; … … 22 23 // Allocator 23 24 pmConceptSpec *pmConceptSpecAlloc(psMetadataItem *blank, // Blank value; contains the name 24 pmConcept ReadFunc read, // Function to call to readthe concept25 pmConcept WriteFunc write // Function to call to writethe concept25 pmConceptParseFunc parse, // Function to call to parse the concept 26 pmConceptFormatFunc format // Function to call to format the concept 26 27 ); 27 28 … … 35 36 // Register a new concept 36 37 bool pmConceptRegister(psMetadataItem *blank, // Blank value; contains the name 37 pmConcept ReadFunc read, // Function to call to readthe concept38 pmConcept WriteFunc write, // Function to call to writethe concept38 pmConceptParseFunc parse, // Function to call to parse the concept 39 pmConceptFormatFunc format, // Function to call to format the concept 39 40 pmConceptLevel level // Level at which to store concept in the FPA hierarchy 40 41 ); 41 42 42 #if 043 43 // Some specificity to reading and writing concepts 44 44 typedef enum { 45 PM_CONCEPT_SOURCE_ALL = 0x00, // Do all sources46 PM_CONCEPT_SOURCE_CAMERA = 0x01, // Do concepts that comefrom the camera information47 PM_CONCEPT_SOURCE_DEFAULTS = 0x02, // Do concepts that comefrom defaults48 PM_CONCEPT_SOURCE_HEADER = 0x04, // Do concepts that comefrom FITS header49 PM_CONCEPT_SOURCE_DATABASE = 0x08 // Do concepts that comefrom database45 PM_CONCEPT_SOURCE_ALL = 0x00, // All concepts 46 PM_CONCEPT_SOURCE_CAMERA = 0x01, // Concept comes from the camera information 47 PM_CONCEPT_SOURCE_DEFAULTS = 0x02, // Concept comes from defaults 48 PM_CONCEPT_SOURCE_HEADER = 0x04, // Concept comes from FITS header 49 PM_CONCEPT_SOURCE_DATABASE = 0x08 // Concept comes from database 50 50 } pmConceptSource; 51 #endif52 51 53 52 // Set blanks, read or write concepts at the appropriate level … … 55 54 ); 56 55 bool pmConceptsReadFPA(pmFPA *fpa, // FPA for which to read concepts 56 pmConceptSource source, // Source for concepts 57 57 psDB *db // Database handle 58 58 ); 59 59 bool pmConceptsWriteFPA(pmFPA *fpa, // FPA for which to write concepts 60 pmConceptSource source, // Source for concepts 60 61 psDB *db // Database handle 61 62 ); … … 63 64 ); 64 65 bool pmConceptsReadChip(pmChip *chip, // Chip for which to read concepts 66 pmConceptSource source, // Source for concepts 65 67 psDB *db // Database handle 66 68 ); 67 69 bool pmConceptsWriteChip(pmChip *chip, // Chip for which to write concepts 70 pmConceptSource source, // Source for concepts 68 71 psDB *db // Database handle 69 72 ); … … 71 74 ); 72 75 bool pmConceptsReadCell(pmCell *cell, // Cell for which to read concepts 76 pmConceptSource source, // Source for concepts 73 77 psDB *db // Database handle 74 78 ); 75 79 bool pmConceptsWriteCell(pmCell *cell, // FPA for which to write concepts 80 pmConceptSource source, // Source for concepts 76 81 psDB *db // Database handle 77 82 ); -
branches/rel10_ifa/psModules/src/astrom/pmConceptsRead.c
r6552 r6570 5 5 #include "pmFPA.h" 6 6 #include "pmConceptsRead.h" 7 #include "psAdditionals.h" 8 7 8 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 9 // File-static functions 10 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 11 12 13 static float parseF32(psMetadataItem *item 14 ) 15 { 16 switch (item->type) { 17 case PS_DATA_F32: 18 return item->data.F32; 19 case PS_DATA_F64: 20 // Assume it's OK to truncate to floating point from double 21 return (float)item->data.F64; 22 case PS_DATA_S32: 23 // Promote to float 24 return (float)item->data.S32; 25 default: 26 psError(PS_ERR_IO, true, "Concept %s (%s) is not of floating point type (%x) --- treating as NaN.\n", 27 item->name, item->comment, item->type); 28 return NAN; 29 } 30 } 31 32 static double parseF64(psMetadataItem *item 33 ) 34 { 35 switch (item->type) { 36 case PS_TYPE_F64: 37 return item->data.F64; 38 case PS_TYPE_F32: 39 // Promote to double 40 return (double)item->data.F32; 41 case PS_TYPE_S32: 42 // Promote to double 43 return (double)item->data.S32; 44 default: 45 psError(PS_ERR_IO, true, "Concept %s (%s) is not of double-precision floating point type (%x) " 46 "--- treating as NaN.\n", item->name, item->comment, item->type); 47 return NAN; 48 } 49 } 50 51 static int parseS32(psMetadataItem *item 52 ) 53 { 54 switch (item->type) { 55 case PS_TYPE_S32: 56 return item->data.S32; 57 case PS_TYPE_F32: 58 psLogMsg(__func__, PS_LOG_WARN, "Concept %s (%s) should be S32, but is F32 --- converting.\n", 59 item->name, comment); 60 return (int)item->data.F32; 61 case PS_TYPE_F64: 62 psLogMsg(__func__, PS_LOG_WARN, "Concept %s (%s) should be S32, but is F64 --- converting.\n", 63 item->name, comment); 64 return (int)item->data.F64; 65 default: 66 psError(PS_ERR_IO, true, "Concept %s (%s) is not of integer type (%x) --- treating as zero.\n", 67 item->name, item->comment, item->type); 68 return 0; 69 } 70 } 71 72 static psString parseString(psMetadataItem *item 73 ) 74 { 75 switch (item->type) { 76 case PS_DATA_STRING: 77 return psMemIncrRefCounter(item->data.V); 78 case PS_DATA_F32: { 79 psString value = NULL; // String to return 80 psStringAppend(&value, "%f", item->data.F32); 81 return value; 82 } 83 case PS_DATA_S32: { 84 psString value = NULL; // String to return 85 psStringAppend(&value, "%d", item->data.S32); 86 return value; 87 } 88 default: 89 psError(PS_ERR_IO, true, "Concept %s (%s) is not of string type (%x) --- treating as " 90 "undefined.\n", name, item->comment, item->type); 91 return psStringCopy(""); 92 } 93 } 94 95 96 // This function gets called for the really boring concepts --- where all you have to do is parse from a 97 // header or database and you don't need to muck around with conversions. There is no similar "formatPlain", 98 // since the type is already known. 99 static psMetadataItem *parsePlain(psMetadataItem *concept, // The concept to parse 100 pmConceptSpec *spec // The concept specification 101 ) 102 { 103 psMetadataItem *blank = spec->blank;// The blank specification, which carries the name, comment, type 104 switch (blank->type) { 105 case PS_DATA_STRING: { 106 psString string = parseString(concept); // Get the string, so I can free it after it goes on the MDI 107 psMetadataItem *item = psMetadataItemAllocStr(blank->name, blank->comment, string); 108 psFree(string); 109 return item; 110 } 111 case PS_DATA_S32: 112 return psMetadataItemAllocS32(blank->name, blank->comment, parseS32(concept)); 113 case PS_DATA_F32: 114 return psMetadataItemAllocF32(blank->name, blank->comment, parseF32(concept)); 115 case PS_DATA_F64: 116 return psMetadataItemAllocF64(blank->name, blank->comment, parseF64(concept)); 117 default: 118 psLogMsg(__func__, PS_LOG_WARN, "Concept %s (%s) is not of a standard type (%x)\n", 119 blank->name, blank->comment, blank->type); 120 return NULL; 121 } 122 } 123 124 // Get the lowest HDU 125 static pmHDU *getLowestHDU(pmFPA *fpa, // The FPA 126 pmChip *chip, // The chip, or NULL 127 pmCell *cell // The cell, or NULL 128 ) 129 { 130 pmHDU *hdu = NULL; // The HDU that's at the lowest level 131 if (cell) { 132 hdu = pmHDUFromCell(cell); 133 } else if (chip) { 134 hdu = pmHDUFromChip(chip); 135 } else if (fpa) { 136 hdu = pmHDUFromFPA(fpa); 137 } 138 139 return hdu; 140 } 141 142 143 // Parse a single concept 144 static bool conceptParse(pmConceptSpec *spec, // The concept specification 145 psMetadataItem *concept, // The concept to parse 146 psMetadata *cameraFormat, // The camera format 147 psMetadata *target, // The target 148 pmFPA *fpa, // The FPA 149 pmChip *chip, // The chip 150 pmCell *cell // The cell 151 ) 152 { 153 if (concept) { 154 psMetadataItem *parsed = NULL; // The parsed concept 155 if (spec->parse) { 156 parsed = spec->parse(concept, spec, cameraFormat, fpa, chip, cell); 157 } else { 158 parsed = parsePlain(concept, spec->blank); 159 } 160 161 // Reformat so that everything's clean 162 if (strcmp(spec->blank->name, parsedItem->name) != 0 || 163 strcmp(spec->blank->comment, parsedItem->comment) != 0) { 164 psMetadataItem *cleaned = NULL; // Item that's been cleaned up --- correct name and comment 165 switch (spec->type) { 166 case PS_DATA_STRING: 167 cleaned = psMetadataItemAllocStr(spec->blank->name, spec->blank->comment, concept->data.V); 168 break; 169 case PS_DATA_S32: 170 cleaned = psMetadataItemAllocS32(spec->blank->name, spec->blank->comment, concept->data.S32); 171 break; 172 case PS_DATA_F32: 173 cleaned = psMetadataItemAllocF32(spec->blank->name, spec->blank->comment, concept->data.F32); 174 break; 175 case PS_DATA_F64: 176 cleaned = psMetadataItemAllocF64(spec->blank->name, spec->blank->comment, concept->data.F64); 177 break; 178 default: 179 cleaned = psMetadataItemAlloc(spec->blank->name, concept->type, spec->blank->comment, 180 concept->data.V); 181 } 182 psFree(parsed); 183 parsed = cleaned; 184 } 185 psMetadataAddItem(target, parsed, PS_LIST_TAIL, PS_META_REPLACE); 186 psFree(parsed); // Drop reference 187 return true; 188 } 189 190 return false; 191 } 192 193 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 194 // Public functions 195 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 196 197 bool pmConceptsReadFromCamera(psMetadata *specs, // The concept specifications 198 pmCell *cell, // The cell 199 psMetadata *target // Place into which to read the concepts 200 ) 201 { 202 if (cell) { 203 pmHDU *hdu = getLowestHDU(NULL, NULL, cell); // The HDU at the lowest level 204 psMetadata *cameraFormat = hdu->format; // The camera format 205 psMetadata *cellConfig = cell->config; // The camera configuration for this cell 206 psMetadataIterator *specsIter = psMetadataIteratorAlloc(specs, PS_LIST_HEAD, NULL); // Iterator 207 psMetadataItem *specItem = NULL; // Item from the specs metadata 208 while ((specItem = psMetadataGetAndIncrement(specsIter))) { 209 pmConceptSpec *spec = specItem->data.V; // The specification 210 psString name = specItem->name; // The concept name 211 psMetadataItem *conceptItem = psMetadataLookup(cellConfig, name); // The concept, or NULL 212 psMetadataItem *value = NULL; // The value of the concept 213 if (conceptItem) { 214 // Check the SOURCE 215 psString nameSource = NULL; // String with the concept name and ".SOURCE" added 216 psStringAppend(nameSource, "%s.SOURCE", name); 217 bool mdok = true; // Status of MD lookup 218 psString source = psMetadataLookupStr(&mdok, cell->config, nameSource); // The source 219 if (mdok && strlen(source)) { 220 if (strcasecmp(source, "HEADER") == 0 && conceptItem->type == PS_DATA_STRING) { 221 value = psMetadataLookup(hdu->header, conceptItem->data.V); 222 } else if (strcasecmp(source, "VALUE") == 0) { 223 value = psMemIncrRefCounter(conceptItem); 224 } else { 225 psError(PS_ERR_IO, true, "%s isn't HEADER or VALUE --- can't read %s\n", source, 226 name); 227 continue; 228 } 229 } else { 230 // Assume it's specified by value 231 value = psMemIncrRefCounter(conceptItem); 232 } 233 conceptParse(spec, value, cameraFormat, target, NULL, NULL, cell); 234 } 235 } 236 psFree(specsIter); 237 return true; 238 } 239 return false; 240 } 241 242 243 bool pmConceptsReadFromDefaults(psMetadata *specs, // The concept specifications 244 pmFPA *fpa, // The FPA 245 pmChip *chip, // The chip 246 pmCell *cell, // The cell 247 psMetadata *target // Place into which to read the concepts 248 ) 249 { 250 bool mdok = true; // Status of MD lookup 251 psMetadata *defaults = psMetadataLookupMD(&mdok, cameraFormat, "DEFAULTS"); // The DEFAULTS spec 252 if (mdok && defaults) { 253 pmHDU *hdu = getLowestHDU(fpa, chip, cell); // The HDU at the lowest level 254 psMetadata *cameraFormat = hdu->format; // The camera format 255 psMetadataIterator *specsIter = psMetadataIteratorAlloc(specs, PS_LIST_HEAD, NULL); // Iterator 256 psMetadataItem *specItem = NULL; // Item from the specs metadata 257 while ((specItem = psMetadataGetAndIncrement(specsIter))) { 258 pmConceptSpec *spec = specItem->data.V; // The specification 259 psString name = specItem->name; // The concept name 260 psMetadataItem *conceptItem = psMetadataLookup(defaults, name); // The concept, or NULL 261 conceptParse(spec, conceptItem, cameraFormat, target, fpa, chip, cell); 262 } 263 psFree(specsIter); 264 return true; 265 } 266 return false; 267 } 268 269 bool pmConceptsReadFromHeader(psMetadata *specs, // The concept specifications 270 pmFPA *fpa, // The FPA 271 pmChip *chip, // The chip 272 pmCell *cell, // The cell 273 psMetadata *target // Place into which to read the concepts 274 ) 275 { 276 bool mdok = true; // Status of MD lookup 277 psMetadata *transSpec = psMetadataLookupMD(&mdok, cameraFormat, "TRANSLATION"); // The TRANSLATION spec 278 if (mdok && transSpec) { 279 pmHDU *hdu = getLowestHDU(fpa, chip, cell); // The HDU at the lowest level 280 psMetadata *cameraFormat = hdu->format; // The camera format 281 psMetadataIterator *specsIter = psMetadataIteratorAlloc(specs, PS_LIST_HEAD, NULL); // Iterator 282 psMetadataItem *specItem = NULL; // Item from the specs metadata 283 while ((specItem = psMetadataGetAndIncrement(specsIter))) { 284 pmConceptSpec *spec = specItem->data.V; // The specification 285 psString name = specItem->name; // The concept name 286 psString keywords = psMetadataLookupStr(&mdok, transSpec, name); // The FITS keywords 287 if (mdok && strlen(keyword) > 0) { 288 // In case there are multiple headers 289 psList *keys = psStringSplit(keywords, " ,;"); // List of keywords 290 psMetadataItem *headerItem = NULL; // The item, to be returned 291 if (keys->n == 1) { 292 // Only one key --- proceed as usual 293 headerItem = psMetadataLookup(hdu->header, keywords); 294 } else { 295 psListIterator *keysIter = psListIteratorAlloc(keys, PS_LIST_HEAD, false); // Iterator 296 psMetadataItem *key = NULL; // Item from iteration 297 psList *values = psListAlloc(void); // List containing the values 298 while ((key = psListGetAndIncrement(keysIter))) { 299 psMetadataItem *value = psMetadataLookup(hdu->header, key); 300 psListAdd(values, PS_LIST_TAIL, value); 301 } 302 psFree(keysIter); 303 headerItem = psMetadataItemAlloc(name, PS_DATA_LIST, specItem->comment, values); 304 psFree(values); 305 } 306 psFree(keys); 307 308 // This will also clean up the name 309 conceptParse(spec, headerItem, cameraFormat, target, fpa, chip, cell); 310 } 311 } 312 psFree(specsIter); 313 return true; 314 } 315 return false; 316 } 317 318 // XXX --- the below code has NOT been tested! 319 bool pmConceptsReadFromDatabase(psMetadata *specs, // The concept specifications 320 pmFPA *fpa, // The FPA 321 pmChip *chip, // The chip 322 pmCell *cell, // The cell 323 psDB *db, // The database handle 324 psMetadata *target // Place into which to read the concepts 325 ) 326 { 327 bool mdok = true; // Status of MD lookup 328 psMetadata *dbSpec = psMetadataLookupMD(&mdok, cameraFormat, "DATABSE"); // The DATABASE spec 329 if (mdok && dbSpec) { 330 pmHDU *hdu = getLowestHDU(fpa, chip, cell); // The HDU at the lowest level 331 psMetadata *cameraFormat = hdu->format; // The camera format 332 psMetadataIterator *specsIter = psMetadataIteratorAlloc(specs, PS_LIST_HEAD, NULL); // Iterator 333 psMetadataItem *specItem = NULL; // Item from the specs metadata 334 while ((specItem = psMetadataGetAndIncrement(specsIter))) { 335 pmConceptSpec *spec = specItem->data.V; // The specification 336 psString name = specItem->name; // The concept name 337 338 psMetadata *dbLookup = psMetadataLookupMD(&mdok, dbSpec, name); 339 if (mdok && dbLookup) { 340 const char *tableName = psMetadataLookupStr(&mdStatus, dbLookup, "TABLE"); // Table name 341 // Names of the "where" columns 342 const char *givenCols = psMetadataLookupStr(&mdStatus, dbLookup, "GIVENDBCOL"); 343 // Values of the "where" columns 344 const char *givenPS = psMetadataLookupStr(&mdStatus, dbLookup, "GIVENPS"); 345 346 // Now, need to get the "given"s 347 if (strlen(givenCols) > 0 || strlen(givenPS) > 0) { 348 psList *cols = psStringSplit(givenCols, ",;"); // List of column names 349 psList *values = psStringSplit(givenPS, ",;"); // List of value names for the columns 350 psMetadata *selection = psMetadataAlloc(); // The stuff to select in the DB 351 if (cols->n != values->n) { 352 psLogMsg(__func__, PS_LOG_WARN, 353 "The GIVENDBCOL and GIVENPS entries for %s do not have " 354 "the same number of entries --- ignored.\n", concept); 355 } else { 356 // Iterators for the lists 357 psListIterator *colsIter = psListIteratorAlloc(cols, PS_LIST_HEAD, false); 358 psListIterator *valuesIter = psListIteratorAlloc(values, PS_LIST_HEAD, false); 359 char *column = NULL; // Name of the column 360 while ((column = psListGetAndIncrement(colsIter))) { 361 char *name = psListGetAndIncrement(valuesIter); // Name for the value 362 if (!strlen(column) || !strlen(name)) { 363 psLogMsg(__func__, PS_LOG_WARN, "One of the columns or value names for %s is " 364 " empty --- ignored.\n", concept); 365 } else { 366 // Search for the value name 367 psMetadataItem *item = pmConceptReadFromHeader(fpa, chip, cell, name); 368 if (! item) { 369 item = pmConceptReadFromDefault(fpa, chip, cell, name); 370 } 371 if (! item) { 372 psLogMsg(__func__, PS_LOG_ERROR, "Unable to find the value name %s for DB" 373 " lookup on %s --- ignored.\n", name, concept); 374 } else { 375 // We need to create a new psMetadataItem. I don't think we can't 376 // simply hack the existing one, since that could conceivably cause 377 // memory leaks 378 psMetadataItem *newItem = psMetadataItemAlloc(concept, item->type, 379 item->comment, 380 item->data.V); 381 psMetadataAddItem(selection, newItem, PS_LIST_TAIL, PS_META_REPLACE); 382 psFree(newItem); 383 } 384 } 385 psFree(name); 386 psFree(column); 387 } // Iterating through the columns 388 psFree(colsIter); 389 psFree(valuesIter); 390 391 psArray *dbResult = psDBSelectRows(db, tableName, selection, 2); // Lookup result 392 // Note that we use limit=2 in order to test if there are multiple rows returned 393 394 psMetadataItem *conceptItem = NULL; // The final result of the DB lookup 395 if (dbResult->n == 0) { 396 psLogMsg(__func__, PS_LOG_WARN, 397 "Unable to find any rows in DB for %s --- ignored\n", concept); 398 } else { 399 if (dbResult-> n > 1) { 400 psLogMsg(__func__, PS_LOG_WARN, 401 "Multiple rows returned in DB lookup for %s --- " 402 " using the first one only.\n", concept); 403 } 404 conceptItem = (psMetadataItem*)dbResult->data[0]; 405 } 406 407 // Now we have the result 408 conceptParse(spec, headerItem, cameraFormat, target, fpa, chip, cell); 409 410 } 411 psFree(cols); 412 psFree(values); 413 } 414 } // Doing the "given"s. 415 416 } // Iterating through the concept specifications 417 psFree(specsIter); 418 419 return true; 420 } 421 return false; 422 } 423 424 425 426 427 #if 0 9 428 10 429 psMetadataItem *pmConceptReadFromCamera(pmCell *cell, // The cell … … 241 660 242 661 243 float pmConceptReadF32(pmFPA *fpa, // The FPA 244 pmChip *chip, // The chip 245 pmCell *cell, // The cell 246 psDB *db, // DB handle 247 const char *name // Name of the concept 248 ) 249 { 250 psMetadataItem *item = pmConceptRead(fpa, chip, cell, db, name); 251 float value = NAN; 252 if (item) { 253 switch (item->type) { 254 case PS_DATA_F32: 255 value = item->data.F32; 256 break; 257 case PS_DATA_F64: 258 // Assume it's OK to truncate to floating point from double 259 value = (float)item->data.F64; 260 break; 261 case PS_DATA_S32: 262 // Promote to float 263 value = (float)item->data.S32; 264 break; 265 default: 266 psError(PS_ERR_IO, true, "Concept %s (%s) is not of floating point type (%x) --- treating as " 267 "undefined.\n", name, item->comment, item->type); 268 } 269 psTrace(__func__, 7, "Adding %s (%s): %f\n", name, item->comment, value); 270 } else { 271 psError(PS_ERR_IO, true, "Concept %s is not defined.\n", name); 272 } 273 274 return value; 275 } 276 277 double pmConceptReadF64(pmFPA *fpa, // The FPA 278 pmChip *chip, // The chip 279 pmCell *cell, // The cell 280 psDB *db, // DB handle 281 const char *name // Name of the concept 282 ) 283 { 284 psMetadataItem *item = pmConceptRead(fpa, chip, cell, db, name); 285 double value = NAN; 286 if (item) { 287 switch (item->type) { 288 case PS_TYPE_F64: 289 value = item->data.F64; 290 break; 291 case PS_TYPE_F32: 292 // Promote to double 293 value = (double)item->data.F32; 294 break; 295 case PS_TYPE_S32: 296 // Promote to double 297 value = (double)item->data.S32; 298 break; 299 default: 300 psError(PS_ERR_IO, true, "Concept %s (%s) is not of double-precision floating point type (%x) " 301 "--- treating as undefined.\n", name, item->comment, item->type); 302 } 303 psTrace(__func__, 7, "Adding %s (%s): %f\n", name, item->comment, value); 304 } else { 305 psError(PS_ERR_IO, true, "Concept %s is not defined.\n", name); 306 } 307 308 return value; 309 } 310 311 int pmConceptReadS32(pmFPA *fpa, // The FPA 312 pmChip *chip, // The chip 313 pmCell *cell, // The cell 314 psDB *db, // DB handle 315 const char *name // Name of the concept 316 ) 317 { 318 psMetadataItem *item = pmConceptRead(fpa, chip, cell, db, name); 319 int value = 0; 320 if (item) { 321 switch (item->type) { 322 case PS_TYPE_S32: 323 value = item->data.S32; 324 break; 325 case PS_TYPE_F32: 326 psLogMsg(__func__, PS_LOG_WARN, "Concept %s (%s) should be S32, but is F32 --- converting.\n", 327 name, comment); 328 value = (int)item->data.F32; 329 break; 330 case PS_TYPE_F64: 331 psLogMsg(__func__, PS_LOG_WARN, "Concept %s (%s) should be S32, but is F64 --- converting.\n", 332 name, comment); 333 value = (int)item->data.F64; 334 break; 335 default: 336 psError(PS_ERR_IO, true, "Concept %s (%s) is not of integer type (%x) --- treating as " 337 "undefined.\n", name, item->comment, item->type); 338 } 339 psTrace(__func__, 7, "Read concept %s (%s): %d\n", name, item->comment, value); 340 } else { 341 psError(PS_ERR_IO, true, "Concept %s is not defined.\n", name); 342 } 343 344 return value; 345 } 346 347 psString pmConceptReadString(pmFPA *fpa, // The FPA 348 pmChip *chip, // The chip 349 pmCell *cell, // The cell 350 psDB *db, // DB handle 351 const char *name // Name of the concept 352 ) 353 { 354 psMetadataItem *item = pmConceptRead(fpa, chip, cell, db, name); 355 psString value = NULL; 356 if (item) { 357 switch (item->type) { 358 case PS_DATA_STRING: 359 value = psMemIncrRefCounter(item->data.V); 360 break; 361 case PS_DATA_F32: 362 psStringAppend(&value, "%f", item->data.F32); 363 break; 364 case PS_DATA_S32: 365 psStringAppend(&value, "%d", item->data.S32); 366 break; 367 default: 368 psError(PS_ERR_IO, true, "Concept %s (%s) is not of string type (%x) --- treating as " 369 "undefined.\n", name, item->comment, item->type); 370 } 371 psTrace(__func__, 7, "Read concept %s (%s): %s\n", name, item->comment, value); 372 } else { 373 psError(PS_ERR_IO, true, "Concept %s is not defined.\n", name); 374 value = psStringCopy(""); 375 } 376 377 return value; 378 } 379 662 #endif -
branches/rel10_ifa/psModules/src/astrom/pmConceptsStandard.c
r6552 r6570 16 16 17 17 18 // Read FPA.RA and translate 19 psMetadataItem *pmConceptRead_FPA_RA(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 20 { 21 double ra = NAN; // The Right Ascension 22 psMetadataItem *raItem = pmConceptRead(fpa, NULL, NULL, db, "FPA.RA"); // The FPA.RA item 23 if (raItem) { 24 switch (raItem->type) { 25 case PS_TYPE_F32: 26 ra = raItem->data.F32; 27 break; 28 case PS_TYPE_F64: 29 ra = raItem->data.F64; 30 break; 31 case PS_DATA_STRING: 32 // Sexagesimal format 18 static double defaultCoordScaling(psMetadataItem *pattern) 19 { 20 if (strcmp(pattern->name, "FPA.RA") == 0) { 21 psLogMsg(__func__, PS_LOG_WARN, "Assuming format for %s is HOURS.\n", pattern->name); 22 return M_PI / 12.0; 23 } else if (strcmp(pattern->name, "FPA.DEC") == 0) { 24 psLogMsg(__func__, PS_LOG_WARN, "Assuming format for %s is DEGREES.\n", pattern->name); 25 return M_PI / 180.0; 26 } else { 27 psAbort("Should never ever get here.\n"); 28 } 29 } 30 31 32 // FPA.RA and FPA.DEC 33 psMetadataItem *pmConceptParse_FPA_Coords(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 34 { 35 assert(concept); 36 assert(pattern); 37 assert(cameraFormat); 38 39 double coords = NAN; // The coordinates 40 switch (concept->type) { 41 case PS_TYPE_F32: 42 coords = concept->data.F32; 43 break; 44 case PS_TYPE_F64: 45 coords = concept->data.F64; 46 break; 47 case PS_DATA_STRING: 48 // Sexagesimal format 49 { 50 int big, medium; 51 float small; 52 // XXX: Upgrade path is to allow dd:mm.mmm 53 if (sscanf(concept->data.V, "%d:%d:%f", &big, &medium, &small) != 3 && 54 sscanf(concept->data.V, "%d %d %f", &big, &medium, &small) != 3) 33 55 { 34 int big, medium; 35 float small; 36 // XXX: Upgrade path is to allow dd:mm.mmm 37 if (sscanf(raItem->data.V, "%d:%d:%f", &big, &medium, &small) != 3 && 38 sscanf(raItem->data.V, "%d %d %f", &big, &medium, &small) != 3) 39 { 40 psError(PS_ERR_IO, true, "Cannot interpret FPA.RA: %s\n", raItem->data.V); 41 break; 42 } 43 ra = abs(big) + (float)medium/60.0 + small/3600.0; 44 if (big < 0) 45 { 46 ra *= -1.0; 47 } 48 } 49 break; 50 default: 51 psError(PS_ERR_IO, true, "FPA.RA is of an unexpected type: %x\n", raItem->type); 52 } 53 54 // How to interpret the RA 55 const psMetadata *camera = fpa->camera; // Camera configuration data 56 bool mdok = true; // Status of MD lookup 57 psMetadata *formats = psMetadataLookupMD(&mdok, camera, "FORMATS"); 58 if (mdok && formats) { 59 psString raFormat = psMetadataLookupStr(&mdok, formats, "FPA.RA"); 60 if (mdok && strlen(raFormat) > 0) { 61 if (strcasecmp(raFormat, "HOURS") == 0) { 62 ra *= M_PI / 12.0; 63 } else if (strcasecmp(raFormat, "DEGREES") == 0) { 64 ra *= M_PI / 180.0; 65 } else if (strcasecmp(raFormat, "RADIANS") == 0) { 66 // No action required 67 } else { 68 psLogMsg(__func__, PS_LOG_WARN, "Don't understand FPA.RA in FORMATS (%s) --- assuming" 69 " HOURS.\n"); 70 ra *= M_PI / 12.0; 71 } 72 } else { 73 psError(PS_ERR_IO, false, "Unable to find FPA.RA in FORMATS --- assuming HOURS.\n"); 74 ra *= M_PI / 12.0; 75 } 76 } else { 77 psError(PS_ERR_IO, false, "Unable to find FORMAT metadata in camera configuration --- " 78 "assuming format for FPA.RA is HOURS.\n"); 79 ra *= M_PI / 12.0; 80 } 81 } else { 82 psError(PS_ERR_IO, false, "Couldn't find FPA.RA.\n"); 83 } 84 85 return psMetadataItemAllocF64("FPA.RA", "Right Ascension of boresight", ra); 86 } 87 88 // Read FPA.DEC and translate 89 psMetadataItem *pmConceptRead_FPA_DEC(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 90 { 91 double dec = NAN; // The DEC 92 psMetadataItem *decItem = pmConceptRead(fpa, NULL, NULL, db, "FPA.DEC"); // The FPA.DEC item 93 if (decItem) { 94 switch (decItem->type) { 95 case PS_TYPE_F32: 96 dec = decItem->data.F32; 97 break; 98 case PS_TYPE_F64: 99 dec = decItem->data.F64; 100 break; 101 case PS_DATA_STRING: 102 // Sexagesimal format 56 psError(PS_ERR_IO, true, "Cannot interpret FPA.RA: %s\n", concept->data.V); 57 break; 58 } 59 coords = abs(big) + (float)medium/60.0 + small/3600.0; 60 if (big < 0) 103 61 { 104 int big, medium; 105 float small; 106 // XXX: Upgrade path is to allow dd:mm.mmm 107 if (sscanf(decItem->data.V, "%d:%d:%f", &big, &medium, &small) != 3 && 108 sscanf(decItem->data.V, "%d %d %f", &big, &medium, &small) != 3) 109 { 110 psError(PS_ERR_IO, true, "Cannot interpret FPA.DEC: %s\n", decItem->data.V); 111 break; 112 } 113 dec = abs(big) + (float)medium/60.0 + small/3600.0; 114 if (big < 0) 115 { 116 dec *= -1.0; 117 } 118 } 119 break; 120 default: 121 psError(PS_ERR_IO, true, "FPA.DEC is of an unexpected type: %x\n", decItem->type); 122 } 123 124 // How to interpret the DEC 125 const psMetadata *camera = fpa->camera; // Camera configuration data 126 bool mdok = true; // Status of MD lookup 127 psMetadata *formats = psMetadataLookupMD(&mdok, camera, "FORMATS"); 128 if (mdok && formats) { 129 psString decFormat = psMetadataLookupStr(&mdok, formats, "FPA.DEC"); 130 if (mdok && strlen(decFormat) > 0) { 131 if (strcasecmp(decFormat, "HOURS") == 0) { 132 dec *= M_PI / 12.0; 133 } else if (strcasecmp(decFormat, "DEGREES") == 0) { 134 dec *= M_PI / 180.0; 135 } else if (strcasecmp(decFormat, "RADIANS") == 0) { 136 // No action required 137 } else { 138 psLogMsg(__func__, PS_LOG_WARN, "Don't understand FPA.DEC in FORMATS (%s) --- " 139 "assuming DEGREES.\n"); 140 dec *= M_PI / 180.0; 141 } 142 } else { 143 psError(PS_ERR_IO, false, "Unable to find FPA.DEC in FORMATS --- assuming DEGREES.\n"); 144 dec *= M_PI / 180.0; 145 } 146 } else { 147 psError(PS_ERR_IO, false, "Unable to find FORMATS metadata in camera configuration --- " 148 "assuming format for FPA.DEC is DEGREES.\n"); 149 dec *= M_PI / 180.0; 150 } 151 } else { 152 psError(PS_ERR_IO, false, "Couldn't find FPA.DEC.\n"); 153 } 154 155 return psMetadataItemAllocF64("FPA.DEC", "Declination of boresight", dec); 156 } 157 158 159 bool pmConceptWrite_FPA_RA(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 160 { 161 double ra = psMetadataLookupF64(NULL, fpa->concepts, "FPA.RA"); // The RA 162 163 // How to interpret the RA 164 const psMetadata *camera = fpa->camera; // Camera configuration data 165 bool mdok = true; // Status of MD lookup 166 psMetadata *formats = psMetadataLookupMD(&mdok, camera, "FORMATS"); 62 coords *= -1.0; 63 } 64 } 65 break; 66 default: 67 psError(PS_ERR_IO, true, "%s concept is of an unexpected type: %x\n", pattern->name, concept->type); 68 return NULL; 69 } 70 71 // How to interpret the coordinates 72 bool mdok = true; // Status of MD lookup 73 psMetadata *formats = psMetadataLookupMD(&mdok, cameraFormat, "FORMATS"); 167 74 if (mdok && formats) { 168 psString raFormat = psMetadataLookupStr(&mdok, formats, "FPA.RA");169 if (mdok && strlen( raFormat) > 0) {170 if (strcasecmp( raFormat, "HOURS") == 0) {171 ra /= M_PI / 12.0;172 } else if (strcasecmp( raFormat, "DEGREES") == 0) {173 ra /= M_PI / 180.0;174 } else if (strcasecmp( raFormat, "RADIANS") == 0) {75 psString format = psMetadataLookupStr(&mdok, formats, blank->name); 76 if (mdok && strlen(format) > 0) { 77 if (strcasecmp(format, "HOURS") == 0) { 78 coords *= M_PI / 12.0; 79 } else if (strcasecmp(format, "DEGREES") == 0) { 80 coords *= M_PI / 180.0; 81 } else if (strcasecmp(format, "RADIANS") == 0) { 175 82 // No action required 176 83 } else { 177 psLogMsg(__func__, PS_LOG_WARN, "Don't understand FPA.RA in FORMATS (%s) --- assuming" 178 " HOURS.\n"); 179 ra /= M_PI / 12.0; 84 coords *= defaultCoordScaling(pattern); 180 85 } 181 86 } else { 182 psError(PS_ERR_IO, false, "Unable to find FPA.RA in FORMATS --- assuming HOURS.\n"); 183 ra /= M_PI / 12.0; 87 coords *= defaultCoordScaling(pattern); 184 88 } 185 89 } else { 186 psError(PS_ERR_IO, false, "Unable to find FORMAT metadata in camera configuration --- " 187 "assuming format for FPA.RA is HOURS.\n"); 188 ra /= M_PI / 12.0; 90 coords *= defaultCoordScaling(pattern); 91 } 92 93 return psMetadataItemAllocF64(pattern->name, pattern->comment, coords); 94 } 95 96 // FPA.RA and FPA.DEC 97 psMetadataItem *pmConceptFormat_FPA_Coords(psMetadataItem *concept, psMetadataItem *pattern, pmConceptSpec *spec, psMetadata *cameraFormat) 98 { 99 assert(concept); 100 assert(pattern); 101 assert(cameraFormat); 102 103 double coords = concept->data.F64; // The coordinates 104 105 // How to interpret the coordinates 106 bool mdok = true; // Status of MD lookup 107 psMetadata *formats = psMetadataLookupMD(&mdok, cameraFormat, "FORMATS"); 108 if (mdok && formats) { 109 psString format = psMetadataLookupStr(&mdok, formats, pattern->name); 110 if (mdok && strlen(format) > 0) { 111 if (strcasecmp(format, "HOURS") == 0) { 112 coords /= M_PI / 12.0; 113 } else if (strcasecmp(format, "DEGREES") == 0) { 114 coords /= M_PI / 180.0; 115 } else if (strcasecmp(format, "RADIANS") == 0) { 116 // No action required 117 } else { 118 coords /= defaultCoordScaling(pattern); 119 } 120 } else { 121 coords /= defaultCoordScaling(pattern); 122 } 123 } else { 124 coords /= defaultCoordScaling(pattern); 189 125 } 190 126 … … 193 129 float small; 194 130 big = (int)ra; 195 medium = (int)(60.0*(ra - (double)big)); 196 small = 3600.0*(ra - (double)big - 60.0 * (double)medium); 197 psString raString = psStringCopy(""); 198 psStringAppend(&raString, "%d:%d:%.2f", big, medium, small); 199 psMetadataItem *raItem = psMetadataItemAllocStr("FPA.RA", "Right Ascension of the boresight", 200 raString); 201 pmConceptWriteItem(fpa, NULL, NULL, db, raItem); 202 psFree(raItem); 203 psFree(raString); 204 205 return true; 206 } 207 208 bool pmConceptWrite_FPA_DEC(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 209 { 210 double dec = psMetadataLookupF64(NULL, fpa->concepts, "FPA.DEC"); // The DEC 211 212 // How to interpret the DEC 213 const psMetadata *camera = fpa->camera; // Camera configuration data 214 bool mdok = true; // Status of MD lookup 215 psMetadata *formats = psMetadataLookupMD(&mdok, camera, "FORMATS"); 216 if (mdok && formats) { 217 psString decFormat = psMetadataLookupStr(&mdok, formats, "FPA.DEC"); 218 if (mdok && strlen(decFormat) > 0) { 219 if (strcasecmp(decFormat, "HOURS") == 0) { 220 dec /= M_PI / 12.0; 221 } else if (strcasecmp(decFormat, "DEGREES") == 0) { 222 dec /= M_PI / 180.0; 223 } else if (strcasecmp(decFormat, "RADIANS") == 0) { 224 // No action required 225 } else { 226 psLogMsg(__func__, PS_LOG_WARN, "Don't understand FPA.DEC in FORMATS (%s) --- assuming" 227 " DEGREES.\n"); 228 dec /= M_PI / 180.0; 229 } 230 } else { 231 psError(PS_ERR_IO, false, "Unable to find FPA.DEC in FORMATS --- assuming DEGREES.\n"); 232 dec /= M_PI / 180.0; 233 } 234 } else { 235 psError(PS_ERR_IO, false, "Unable to find FORMAT metadata in camera configuration --- " 236 "assuming format for FPA.DEC is HOURS.\n"); 237 dec /= M_PI / 12.0; 238 } 239 240 // We choose to write sexagesimal format 241 int big, medium; 242 float small; 243 big = (int)dec; 244 medium = (int)(60.0*(dec - (double)big)); 245 small = 3600.0*(dec - (double)big - 60.0 * (double)medium); 246 psString decString = psStringCopy(""); 247 psStringAppend(&decString, "%d:%d:%.2f", big, medium, small); 248 psMetadataItem *decItem = psMetadataItemAllocStr("FPA.DEC", "Right Ascension of the boresight", 249 decString); 250 pmConceptWriteItem(fpa, NULL, NULL, db, decItem); 251 psFree(decItem); 252 psFree(decString); 253 254 return true; 255 } 256 257 258 psMetadataItem *pmConceptRead_CELL_TRIMSEC(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 259 { 131 medium = (int)(60.0*(coords - (double)big)); 132 small = 3600.0*(coords - (double)big - 60.0 * (double)medium); 133 psString coordString = NULL; // String with the coordinates in sexagesimal format 134 psStringAppend(&coordString, "%d:%d:%.2f", big, medium, small); 135 psMetadataItem *coordItem = psMetadataItemAllocStr(pattern->name, pattern->comment, coordString); 136 psFree(coordString); 137 138 return coordItem; 139 } 140 141 142 psMetadataItem *pmConceptParse_CELL_TRIMSEC(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 143 { 144 assert(concept); 145 assert(cell); 146 assert(pattern); 147 148 psMetadata *cellConfig = cell->config; // The cell configuration 260 149 psRegion *trimsec = psAlloc(sizeof(psRegion)); // Make space for a psRegion (usually passed by value) 261 150 262 psMetadataItem *secItem = pmConceptRead(fpa, chip, cell, db, "CELL.TRIMSEC"); 263 if (! secItem) { 264 psError(PS_ERR_IO, false, "Couldn't find CELL.TRIMSEC.\n"); 265 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 266 } else if (secItem->type != PS_DATA_STRING) { 267 psError(PS_ERR_IO, true, "CELL.TRIMSEC is not of type STR (%x)\n", secItem->type); 151 if (concept->type != PS_DATA_STRING) { 152 psError(PS_ERR_IO, true, "CELL.TRIMSEC after read is not of type STR (%x)\n", concept->type); 268 153 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 269 154 } else { 270 psString section = secItem->data.V; // The section string 271 272 psMetadataItem *sourceItem = pmConceptRead(fpa, chip, cell, db, "CELL.TRIMSEC.SOURCE"); 273 if (! sourceItem) { 274 psError(PS_ERR_IO, false, "Couldn't find CELL.TRIMSEC.SOURCE.\n"); 275 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 276 } else if (sourceItem->type != PS_DATA_STRING) { 277 psError(PS_ERR_IO, true, "CELL.TRIMSEC.SOURCE is not of type STR (%x)\n", sourceItem->type); 278 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 279 } else { 280 psString source = sourceItem->data.V; // The source string 281 282 if (strcasecmp(source, "VALUE") == 0) { 283 *trimsec = psRegionFromString(section); 284 } else if (strcasecmp(source, "HEADER") == 0) { 285 psMetadata *header = NULL; // The FITS header 286 if (cell->hdu) { 287 header = cell->hdu->header; 288 } else if (chip->hdu) { 289 header = chip->hdu->header; 290 } else if (fpa->hdu) { 291 header = fpa->hdu->header; 292 } 293 if (! header) { 294 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 295 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 296 } else { 297 bool mdok = true; // Status of MD lookup 298 psString secValue = psMetadataLookupStr(&mdok, header, section); 299 if (! mdok || ! secValue) { 300 psError(PS_ERR_IO, false, "Unable to locate header %s\n", section); 301 *trimsec = psRegionSet(0.0, 0.0, 0.0, 0.0); 302 } else { 303 *trimsec = psRegionFromString(secValue); 304 } 305 } 306 } else { 307 psError(PS_ERR_IO, true, "CELL.TRIMSEC.SOURCE (%s) is not HEADER or VALUE --- trying " 308 "VALUE.\n", source); 309 *trimsec = psRegionFromString(section); 310 } // Value of CELL.TRIMSEC.SOURCE 311 } // Looking up CELL.TRIMSEC.SOURCE 312 } // Looking up CELL.TRIMSEC 313 314 psMetadataItem *item = psMetadataItemAllocPtr("CELL.TRIMSEC", PS_DATA_UNKNOWN, "Trim section", trimsec); 155 *trimsec = psRegionFromString(concept->data.V); 156 } 157 158 psMetadataItem *item = psMetadataItemAllocPtr(pattern->name, PS_DATA_UNKNOWN, pattern->comment, trimsec); 315 159 psFree(trimsec); 316 160 return item; 317 161 } 318 162 319 320 psMetadataItem *pmConceptRead_CELL_BIASSEC(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 321 { 163 psMetadataItem *pmConceptParse_CELL_BIASSEC(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 164 { 165 assert(concept); 166 assert(cell); 167 assert(pattern); 168 psMetadata *cellConfig = cell->config; // The cell configuration 169 322 170 psList *biassecs = psListAlloc(NULL); // List of bias sections 323 171 psMetadataItem *item = psMetadataItemAlloc("CELL.BIASSEC", PS_DATA_LIST, "Bias sections", biassecs); 324 172 psFree(biassecs); // Drop reference 325 173 326 psMetadataItem *secItem = pmConceptRead(fpa, chip, cell, db, "CELL.BIASSEC"); 327 if (! secItem) { 328 psError(PS_ERR_IO, false, "Couldn't find CELL.BIASSEC.\n"); 329 return item; 330 } 331 if (secItem->type != PS_DATA_STRING) { 332 psError(PS_ERR_IO, true, "CELL.BIASSEC is not of type STR (%x)\n", secItem->type); 333 return item; 334 } 335 336 psString sections = secItem->data.V; // The section string 337 338 psMetadataItem *sourceItem = pmConceptRead(fpa, chip, cell, db, "CELL.BIASSEC.SOURCE"); 339 if (! sourceItem) { 340 psError(PS_ERR_IO, false, "Couldn't find CELL.BIASSEC.SOURCE.\n"); 341 return item; 342 } else if (sourceItem->type != PS_DATA_STRING) { 343 psError(PS_ERR_IO, true, "CELL.BIASSEC.SOURCE is not of type STR (%x)\n", sourceItem->type); 344 return item; 345 } 346 347 psString source = sourceItem->data.V; // The source string 348 349 if (! strcasecmp(source, "NONE")) { 350 return item; // There is no biassec 351 } 352 353 psList *secList = psStringSplit(sections, " ;"); // List of sections 354 psListIterator *secIter = psListIteratorAlloc(secList, PS_LIST_HEAD, false); // Iterator over 355 // sections 356 psString aSection = NULL; // A section from the list 357 while ((aSection = psListGetAndIncrement(secIter))) { 358 psRegion *region = psAlloc(sizeof(psRegion)); // Make space for a psRegion (usually passed by 359 // value) 360 361 if (strcasecmp(source, "VALUE") == 0) { 362 *region = psRegionFromString(aSection); 363 } else if (strcasecmp(source, "HEADER") == 0) { 364 psMetadata *header = NULL; // The FITS header 365 if (cell->hdu) { 366 header = cell->hdu->header; 367 } else if (chip->hdu) { 368 header = chip->hdu->header; 369 } else if (fpa->hdu) { 370 header = fpa->hdu->header; 371 } 372 if (! header) { 373 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 374 *region = psRegionSet(0.0,0.0,0.0,0.0); 174 switch (concept->type) { 175 case PS_DATA_STRING: { 176 psList *regions = psStringSplit(concept->data.V, " ;"); // List of regions 177 psListIterator *regionsIter = psListIteratorAlloc(regions, PS_LIST_HEAD, false); // Iterator 178 psString regionString = NULL; // Region string from iteration 179 while ((regionString = psListGetAndIncrement(regionsIter))) { 180 psRegion *region = psAlloc(sizeof(psRegion)); // The region 181 *region = psRegionFromString(regionString); 182 psListAdd(biassecs, PS_LIST_TAIL, region); 183 psFree(region); // Drop reference 184 } 185 psFree(regionsIter); 186 psFree(regions); 187 break; 188 } 189 case PS_DATA_LIST: { 190 psList *regions = concept->data.V; // The list of regions 191 psListIterator *regionsIter = psListIteratorAlloc(regions, PS_LIST_HEAD, false); // Iterator 192 psMetadataItem *regionItem = NULL; // Item from list iteration 193 while ((regionItem = psListGetAndIncrement(regionsIter))) { 194 if (regionItem->type != PS_DATA_STRING) { 195 psLogMsg(__func__, PS_LOG_WARN, "CELL.BIASSEC member is not of type STR --- ignored.\n"); 196 continue; 197 } 198 psRegion *region = psAlloc(sizeof(psRegion)); // The region 199 *region = psRegionFromString(regionItem->data.V); 200 psListAdd(biassecs, PS_LIST_TAIL, region); 201 psFree(region); // Drop reference 202 } 203 psFree(regionsIter); 204 break; 205 } 206 default: 207 psError(PS_ERR_IO, true, "CELL.BIASSEC after read is not of type STRING or LIST --- assuming " 208 "blank.\n"); 209 } 210 211 psMetadataItem *item = psMetadataItemAllocPtr(pattern->name, PS_DATA_LIST, pattern->comment, biassecs); 212 psFree(biassecs); 213 return item; 214 } 215 216 // CELL.XBIN and CELL.YBIN 217 psMetadataItem *pmConceptParse_CELL_BINNING(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 218 { 219 assert(concept); 220 assert(pattern); 221 222 int binning = 1; // Binning factor in x 223 if (concept->type == PS_DATA_STRING) { 224 psString binString = concept->data.V; // The string containing the binning 225 if ((strcmp(pattern->name, "CELL.XBIN") == 0 && sscanf(binString, "%d %*d", &binning) != 1 && 226 sscanf(binString, "%d,%*d", &binning) != 1) || 227 (strcmp(pattern->name, "CELL.YBIN") == 0 && sscanf(binString, "%*d %d", &binning) != 1 && 228 sscanf(binString, "%*d,%d", &binning) != 1) { 229 psError(PS_ERR_IO, true, "Unable to parse string to get %s: %s\n", pattern->name, binString) 230 ; 231 } 232 } else if (concept->type == PS_TYPE_S32) { 233 binning = concept->data.S32; 375 234 } else { 376 bool mdok = true; // Status of MD lookup 377 psString secValue = psMetadataLookupStr(&mdok, header, aSection); 378 if (! mdok || ! secValue) { 379 psError(PS_ERR_IO, false, "Unable to locate header %s\n", aSection); 380 *region = psRegionSet(0.0,0.0,0.0,0.0); 381 } else { 382 *region = psRegionFromString(secValue); 383 } 384 } 385 } else { 386 psError(PS_ERR_IO, true, "CELL.BIASSEC.SOURCE (%s) is not HEADER or VALUE --- trying " 387 "VALUE.\n", source); 388 *region = psRegionFromString(aSection); 389 } // Value of CELL.BIASSEC.SOURCE 390 391 psListAdd(biassecs, PS_LIST_TAIL, region); 392 psFree(region); 393 } // Iterating over multiple sections 394 psFree(secIter); 395 psFree(secList); 396 397 return item; 398 } 399 400 401 psMetadataItem *pmConceptRead_CELL_XBIN(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 402 { 403 int xBin = 1; // Binning factor in x 404 psMetadataItem *binItem = pmConceptRead(fpa, chip, cell, db, "CELL.XBIN"); 405 if (! binItem) { 406 psError(PS_ERR_IO, false, "Couldn't find CELL.XBIN.\n"); 407 } else if (binItem->type == PS_DATA_STRING) { 408 psString binString = binItem->data.V; // The string containing the binning 409 if (sscanf(binString, "%d %*d", &xBin) != 1 && 410 sscanf(binString, "%d,%*d", &xBin) != 1) { 411 psError(PS_ERR_IO, true, "Unable to read string to get x binning: %s\n", binString); 412 } 413 } else if (binItem->type == PS_TYPE_S32) { 414 xBin = binItem->data.S32; 415 } else { 416 psError(PS_ERR_IO, true, "Note sure how to interpret CELL.XBIN of type %x --- assuming 1.\n", 417 binItem->type); 418 } 419 420 return psMetadataItemAllocS32("CELL.XBIN", "Binning in x", xBin); 421 } 422 423 psMetadataItem *pmConceptRead_CELL_YBIN(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 424 { 425 int yBin = 1; // Binning factor in y 426 psMetadataItem *binItem = pmConceptRead(fpa, chip, cell, db, "CELL.YBIN"); 427 if (! binItem) { 428 psError(PS_ERR_IO, false, "Couldn't find CELL.YBIN.\n"); 429 } else if (binItem->type == PS_DATA_STRING) { 430 psString binString = binItem->data.V; // The string containing the binning 431 if (sscanf(binString, "%*d %d", &yBin) != 1 && 432 sscanf(binString, "%*d,%d", &yBin) != 1) { 433 psError(PS_ERR_IO, true, "Unable to read string to get y binning: %s\n", binString); 434 } 435 } else if (binItem->type == PS_TYPE_S32) { 436 yBin = binItem->data.S32; 437 } else { 438 psError(PS_ERR_IO, true, "Note sure how to interpret CELL.YBIN of type %x --- assuming 1.\n", 439 binItem->type); 440 } 441 442 return psMetadataItemAllocS32("CELL.YBIN", "Binning in y", yBin); 443 } 444 445 psMetadataItem *pmConceptRead_CELL_TIMESYS(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 446 { 235 psError(PS_ERR_IO, true, "Note sure how to parse %s of type %x --- assuming 1.\n", pattern->name, 236 binItem->type); 237 } 238 239 return psMetadataItemAllocS32(pattern->name, pattern->comment, binning); 240 } 241 242 243 psMetadataItem *pmConceptParse_CELL_TIMESYS(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 244 { 245 assert(concept); 246 assert(pattern); 247 447 248 psTimeType timeSys = PS_TIME_UTC; // The time system 448 psString sys = pmConceptReadString(fpa, chip, cell, db, "CELL.TIMESYS"); // The time system as a string 449 if (! sys || strlen(sys) <= 0) { 249 if (concept->type != PS_DATA_STRING || strlen(sys) <= 0) { 450 250 psError(PS_ERR_IO, true, "Can't interpret CELL.TIMESYS --- assuming UTC.\n"); 451 251 } else if (strcasecmp(sys, "TAI") == 0) { … … 462 262 463 263 psFree(sys); 464 return psMetadataItemAllocS32("CELL.TIMESYS", "Time system", timeSys); 465 } 466 467 468 psMetadataItem *pmConceptRead_CELL_TIME(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 469 { 264 return psMetadataItemAllocS32(pattern->name, pattern->comment, timeSys); 265 } 266 267 268 psMetadataItem *pmConceptParse_CELL_TIME(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 269 { 270 assert(concept); 271 assert(cameraFormat); 272 assert(cell); 273 470 274 // Need CELL.TIMESYS first 471 275 bool mdok = false; // Result of MD lookup … … 475 279 timeSys = PS_TIME_UTC; 476 280 } 281 282 // Get format 283 bool mdok = true; // Status of MD lookup 284 psMetadata *formats = psMetadataLookupMD(&mdok, cameraFormat, "FORMATS"); 285 if (!mdok || !formats) { 286 psError(PS_ERR_IO, false, "Unable to find FORMATS in camera configuration.\n"); 287 return NULL; 288 } 289 290 psString timeFormat = psMetadataLookupStr(&mdok, formats, "CELL.TIME"); 291 if (!mdok || strlen(timeFormat) == 0) { 292 psError(PS_ERR_IO, false, "Unable to find CELL.TIME in FORMATS.\n"); 293 return NULL; 294 } 295 477 296 psTime *time = NULL; // The time 478 479 psMetadataItem *timeItem = pmConceptRead(fpa, chip, cell, db, "CELL.TIME"); 480 if (! timeItem) { 481 psError(PS_ERR_IO, false, "Couldn't find CELL.TIME.\n"); 482 } else { 483 // Get format 484 const psMetadata *camera = fpa->camera; // The camera configuration data 485 bool mdok = true; // Status of MD lookup 486 psMetadata *formats = psMetadataLookupMD(&mdok, camera, "FORMATS"); 487 if (mdok && formats) { 488 psString timeFormat = psMetadataLookupStr(&mdok, formats, "CELL.TIME"); 489 if (mdok && strlen(timeFormat) > 0) { 297 switch (concept->type) { 298 case PS_DATA_LIST: { 299 // The date and time are stored separately 300 // Assume the date is first and the time second 301 psList *dateTime = concept->data.V; // The list containing items for date and time 302 psMetadataItem *dateItem = psListGet(dateTime, PS_LIST_HEAD); // Item containing the date 303 psMetadataItem *timeItem = psListGet(dateTime, PS_LIST_HEAD + 1); // Item containing the time 304 if (dateItem->type != PS_DATA_STRING) { 305 psError(PS_ERR_IO, true, "Date is not of type STR.\n"); 306 return NULL; 307 } 308 psString dateString = dateItem->data.V; // The string with the date 309 int day = 0, month = 0, year = 0; 310 if (sscanf(dateString, "%d-%d-%d", &day, &month, &year) != 3 && 311 sscanf(dateString, "%d/%d/%d", &day, &month, &year) != 3) { 312 psError(PS_ERR_IO, true, "Unable to read date: %s\n", dateString); 313 return NULL; 314 } 315 if (strstr(timeFormat, "BACKWARDS")) { 316 int temp = day; 317 day = year; 318 year = temp; 319 } 320 if (strstr(timeFormat, "PRE2000") || year < 2000) { 321 year += 2000; 322 } 323 324 psString timeString = NULL; // The string with the time 325 if (timeItem->type == PS_DATA_STRING) { 326 timeString = timeItem->data.V; 327 } else { 328 // Assume that time is specified in Second of Day (!) 329 double seconds = NAN; 490 330 switch (timeItem->type) { 491 case PS_DATA_STRING: { 492 psString timeString = timeItem->data.V; // String with the time 493 if (strcasecmp(timeFormat, "ISO") == 0) { 494 // timeString contains an ISO time 495 time = psTimeFromISO(timeString, timeSys); 496 } else if (strcasecmp(timeFormat, "JD") == 0) { 497 double timeValue = strtod (timeString, NULL); 498 time = psTimeFromJD(timeValue); 499 } else if (strcasecmp(timeFormat, "MJD") == 0) { 500 double timeValue = strtod (timeString, NULL); 501 time = psTimeFromMJD(timeValue); 502 } else if (strstr(timeFormat, "SEPARATE")) { 503 // timeString contains headers for the date and time 504 psMetadata *header = NULL; // The FITS header 505 if (cell->hdu) { 506 header = cell->hdu->header; 507 } else if (chip->hdu) { 508 header = chip->hdu->header; 509 } else if (fpa->hdu) { 510 header = fpa->hdu->header; 511 } 512 if (! header) { 513 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 514 } else { 515 // Get the headers 516 char *stuff1 = strpbrk(timeString, " ,;"); 517 psString dateName = psStringNCopy(timeString, 518 strlen(timeString) - strlen(stuff1)); 519 char *stuff2 = strpbrk(stuff1, "abcdefghijklmnopqrstuvwxyz" 520 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); 521 psString timeName = psStringCopy(stuff2); 522 523 bool mdok = true; // Status of MD lookup 524 psString dateString = psMetadataLookupStr(&mdok, header, dateName); 525 psFree(dateName); 526 int day = 0, month = 0, year = 0; 527 if (sscanf(dateString, "%d-%d-%d", &day, &month, &year) != 3 && 528 sscanf(dateString, "%d/%d/%d", &day, &month, &year) != 3) { 529 psError(PS_ERR_IO, true, "Unable to read date: %s\n", dateString); 530 } else { 531 if (strstr(timeFormat, "BACKWARDS")) { 532 int temp = day; 533 day = year; 534 year = temp; 535 } 536 if (strstr(timeFormat, "PRE2000") || year < 2000) { 537 year += 2000; 538 } 539 540 psMetadataItem *timeItem = psMetadataLookup(header, timeName); 541 if (! timeItem) { 542 psError(PS_ERR_IO, false, "Unable to find time header: %s\n", 543 timeName); 544 } else if (timeItem->type == PS_DATA_STRING) { 545 // Time is a string, in the usual way: 546 psStringAppend(&dateString, "T%s", timeItem->data.V); 547 } else { 548 // Assume that time is specified in Second of Day 549 double seconds = NAN; 550 switch (timeItem->type) { 551 case PS_TYPE_S32: 552 seconds = timeItem->data.S32; 553 break; 554 case PS_TYPE_F32: 555 seconds = timeItem->data.F32; 556 break; 557 case PS_TYPE_F64: 558 seconds = timeItem->data.F64; 559 break; 560 default: 561 psError(PS_ERR_IO, true, "Time header (%s) is not of an " 562 "expected type: %x\n", timeName, timeItem->type); 563 } 564 // Now print to timeString as "hh:mm:ss.ss" 565 int hours = seconds / 3600; 566 seconds -= (double)hours * 3600.0; 567 int minutes = seconds / 60; 568 seconds -= (double)minutes * 60.0; 569 psStringAppend(&dateString, "T%02d:%02d:%02f", hours, minutes, 570 seconds); 571 } 572 time = psTimeFromISO(dateString, timeSys); 573 } // Reading date and time 574 psFree(timeName); 575 } // Reading headers 576 } else { 577 psError(PS_ERR_IO, true, "Not sure how to parse CELL.TIME (%s) --- trying " 578 "ISO\n", timeString); 579 time = psTimeFromISO(timeString, timeSys); 580 } // Interpreting the time string 581 } 331 case PS_TYPE_S32: 332 seconds = timeItem->data.S32; 582 333 break; 583 case PS_TYPE_F32: { 584 double timeValue = (double)timeItem->data.F32; 585 if (strcasecmp(timeFormat, "JD") == 0) { 586 time = psTimeFromJD(timeValue); 587 } else if (strcasecmp(timeFormat, "MJD") == 0) { 588 time = psTimeFromMJD(timeValue); 589 } else { 590 psError(PS_ERR_IO, true, "Not sure how to parse CELL.TIME (%f) --- trying " 591 "JD\n", timeValue); 592 time = psTimeFromJD(timeValue); 593 } 594 } 334 case PS_TYPE_F32: 335 seconds = timeItem->data.F32; 595 336 break; 596 case PS_TYPE_F64: { 597 double timeValue = (double)timeItem->data.F64; 598 if (strcasecmp(timeFormat, "JD") == 0) { 599 time = psTimeFromJD(timeValue); 600 } else if (strcasecmp(timeFormat, "MJD") == 0) { 601 time = psTimeFromMJD(timeValue); 602 } else { 603 psError(PS_ERR_IO, true, "Not sure how to parse CELL.TIME (%f) --- trying " 604 "JD\n", timeValue); 605 time = psTimeFromJD(timeValue); 606 } 607 } 337 case PS_TYPE_F64: 338 seconds = timeItem->data.F64; 608 339 break; 609 340 default: 610 psError(PS_ERR_IO, true, "Unable to parse CELL.TIME.\n"); 341 psError(PS_ERR_IO, true, "Time is not of an expected type: %x\n", timeItem->type); 342 return NULL; 611 343 } 344 // Now print to timeString as "hh:mm:ss.ss" 345 int hours = seconds / 3600; 346 seconds -= (double)hours * 3600.0; 347 int minutes = seconds / 60; 348 seconds -= (double)minutes * 60.0; 349 psStringAppend(&timeString, "%02d:%02d:%02f", hours, minutes, seconds); 350 } 351 psString dateTimeString = NULL; 352 psStringAppend(&dateTimeString, "%sT%s", dateString, timeString); 353 time = psTimeFromISO(dateTimeString, timeSys); 354 break; 355 } 356 case PS_DATA_STRING: { 357 psString timeString = concept->data.V; // String with the time 358 if (strcasecmp(timeFormat, "ISO") == 0) { 359 // timeString contains an ISO time 360 time = psTimeFromISO(timeString, timeSys); 361 } else if (strcasecmp(timeFormat, "JD") == 0) { 362 double timeValue = strtod (timeString, NULL); 363 time = psTimeFromJD(timeValue); 364 } else if (strcasecmp(timeFormat, "MJD") == 0) { 365 double timeValue = strtod (timeString, NULL); 366 time = psTimeFromMJD(timeValue); 612 367 } else { 613 psError(PS_ERR_IO, false, "Unable to find CELL.TIME in FORMATS.\n"); 614 } // Getting the format 615 } else { 616 psError(PS_ERR_IO, false, "Unable to find FORMATS in camera configuration.\n"); 617 } // Getting the formats 618 } // Getting CELL.TIME 619 620 psMetadataItem *item = psMetadataItemAllocPtr("CELL.TIME", PS_DATA_TIME, "Time of exposure", time); 368 psError(PS_ERR_IO, true, "Not sure how to parse CELL.TIME (%s) --- trying " 369 "ISO\n", timeString); 370 time = psTimeFromISO(timeString, timeSys); 371 } // Interpreting the time string 372 break; 373 } 374 case PS_TYPE_F32: { 375 double timeValue = (double)concept->data.F32; 376 if (strcasecmp(timeFormat, "JD") == 0) { 377 time = psTimeFromJD(timeValue); 378 } else if (strcasecmp(timeFormat, "MJD") == 0) { 379 time = psTimeFromMJD(timeValue); 380 } else { 381 psError(PS_ERR_IO, true, "Not sure how to parse CELL.TIME (%f) --- trying " 382 "JD\n", timeValue); 383 time = psTimeFromJD(timeValue); 384 } 385 break; 386 } 387 case PS_TYPE_F64: { 388 double timeValue = (double)concept->data.F64; 389 if (strcasecmp(timeFormat, "JD") == 0) { 390 time = psTimeFromJD(timeValue); 391 } else if (strcasecmp(timeFormat, "MJD") == 0) { 392 time = psTimeFromMJD(timeValue); 393 } else { 394 psError(PS_ERR_IO, true, "Not sure how to parse CELL.TIME (%f) --- trying " 395 "JD\n", timeValue); 396 time = psTimeFromJD(timeValue); 397 } 398 break; 399 } 400 default: 401 psError(PS_ERR_IO, true, "Unable to parse CELL.TIME.\n"); 402 return NULL; 403 } 404 405 psMetadataItem *item = psMetadataItemAllocPtr(pattern->name, PS_DATA_TIME, pattern->comment, time); 621 406 psFree(time); 622 407 return item; … … 624 409 625 410 // Correct a position --- in case the user wants FORTRAN indexing (like the FITS standard...) 626 static int fortranCorr(p mFPA *fpa, // FPA, contains the camera configuration411 static int fortranCorr(psMetadata *cameraFormat, // The camera format description 627 412 const char *name // Name of concept to check for FORTRAN indexing 628 413 ) 629 414 { 630 415 bool mdok = false; // Result of MD lookup 631 psMetadata *formats = psMetadataLookupMD(&mdok, fpa->camera, "FORMATS");416 psMetadata *formats = psMetadataLookupMD(&mdok, cameraFormat, "FORMATS"); 632 417 if (mdok && formats) { 633 418 psString format = psMetadataLookupStr(&mdok, formats, name); … … 639 424 } 640 425 641 psMetadataItem *pmConceptRead_CELL_X0(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 642 { 643 int x0 = pmConceptReadS32(fpa, chip, cell, db, "CELL.X0"); 644 x0 += fortranCorr(fpa, "CELL.X0"); 645 return psMetadataItemAllocS32("CELL.X0", "Position of (0,0) on the chip", x0); 646 } 647 648 649 psMetadataItem *pmConceptRead_CELL_Y0(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 650 { 651 int y0 = pmConceptReadS32(fpa, chip, cell, db, "CELL.Y0"); 652 y0 += fortranCorr(fpa, "CELL.X0"); 653 return psMetadataItemAllocS32("CELL.Y0", "Position of (0,0) on the chip", y0); 654 } 655 656 657 bool pmConceptWrite_CELL_TRIMSEC(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 658 { 659 psMetadataItem *trimsecItem = psMetadataLookup(cell->concepts, "CELL.TRIMSEC"); 660 psRegion *trimsec = trimsecItem->data.V; // The trimsec region 661 psString source = pmConceptReadString(fpa, chip, cell, db, "CELL.TRIMSEC.SOURCE"); // The source string 662 663 if (strcasecmp(source, "VALUE") == 0) { 664 // Check that it's the same value as stored in the camera 665 psString checkString = psMetadataLookupStr(NULL, cell->config, "CELL.TRIMSEC"); 666 psRegion checkRegion = psRegionFromString(checkString); 667 if (! COMPARE_REGIONS(&checkRegion, trimsec)) { 668 psError(PS_ERR_IO, true, "Target CELL.TRIMSEC is specified by value, and values don't " 669 "match.\n"); 670 return false; 671 } 672 return true; 673 } 674 675 if (strcasecmp(source, "HEADER") == 0) { 676 psMetadata *header = NULL; // The FITS header 677 if (cell->hdu) { 678 header = cell->hdu->header; 679 } else if (chip->hdu) { 680 header = chip->hdu->header; 681 } else if (fpa->hdu) { 682 header = fpa->hdu->header; 683 } 684 if (! header) { 685 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 686 return false; 687 } 688 psMetadataAddItem(header, trimsecItem, PS_LIST_TAIL, PS_META_REPLACE); 689 return true; 690 } 691 692 psError(PS_ERR_IO, true, "CELL.TRIMSEC.SOURCE (%s) is not HEADER or VALUE.\n", source); 693 return false; 694 } 695 696 bool pmConceptWrite_CELL_BIASSEC(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 697 { 698 psMetadataItem *biassecItem = psMetadataLookup(cell->concepts, "CELL.BIASSEC"); 699 psList *biassecs = biassecItem->data.V; // The biassecs region list 700 701 if (biassecs->n == 0) { 702 psMetadataItem *noneItem = psMetadataItemAllocStr("CELL.BIASSEC", "Bias section", "NONE"); 703 pmConceptWriteItem(fpa, chip, cell, db, noneItem); 704 return true; 705 } 706 707 psString source = pmConceptReadString(fpa, chip, cell, db, "CELL.TRIMSEC.SOURCE"); // The source string 708 709 if (strcasecmp(source, "VALUE") == 0) { 710 // Check that it's the same value as stored in the camera 711 psString checkString = psMetadataLookupStr(NULL, cell->config, "CELL.BIASSEC"); 712 psList *checkList = psStringSplit(checkString, " ;"); 713 if (biassecs->n != checkList->n) { 714 psError(PS_ERR_IO, true, "Target CELL.BIASSEC is specified by value, but number of " 715 "entries doesn't match.\n"); 716 psFree(checkList); 717 return false; 718 } 719 720 // We don't care if the order matches or not 721 psVector *check = psVectorAlloc(biassecs->n, PS_TYPE_U8); // Vector to mark regions off 722 for (int i = 0; i < check->n; i++) { 723 check->data.U8[i] = 0; 724 } 725 psListIterator *biassecsIter = psListIteratorAlloc(biassecs, PS_LIST_HEAD, false); // Iterator 726 psListIterator *checkListIter = psListIteratorAlloc(checkList, PS_LIST_HEAD, false); 727 psRegion *biassec = NULL; // Region from iteration 728 while ((biassec = psListGetAndIncrement(biassecsIter))) { 729 psListIteratorSet(checkListIter, PS_LIST_HEAD); 730 psString checkRegionString = NULL; // Region string from iteration 731 int i = 0; // Counter 732 while ((checkRegionString = psListGetAndIncrement(checkListIter))) { 733 psRegion checkRegion = psRegionFromString(checkRegionString); 734 psTrace(__func__, 7, "Checking [%.0f:%.0f,%.0f:%.0f] against " 735 "[%.0f:%.0f,%.0f:%.0f]\n", biassec->x0, biassec->x1, biassec->y0, 736 biassec->y1, checkRegion.x0, checkRegion.x1, checkRegion.y0, 737 checkRegion.y1); 738 if (COMPARE_REGIONS(biassec, &checkRegion)) { 739 check->data.U8[i] = 1; 740 i++; 741 break; 742 } 743 i++; 744 } 745 } 746 747 bool allMatch = true; // Does everything match? 748 for (int i = 0; i < check->n; i++) { 749 if (check->data.U8[i] == 0) { 750 psError(PS_ERR_IO, true, "Target CELL.BIASSEC is specified by value, but values " 751 "don't match.\n"); 752 allMatch = false; 753 } 754 } 755 // Clean up 756 psFree(checkListIter); 757 psFree(checkList); 758 psFree(biassecsIter); 759 psFree(check); 760 761 return allMatch; 762 } 763 764 if (strcasecmp(source, "HEADER") == 0) { 765 psString keywordsString = psMetadataLookupStr(NULL, cell->config, "CELL.BIASSEC"); 766 psList *keywords = psStringSplit(keywordsString, " ,;"); 767 if (biassecs->n != keywords->n) { 768 psError(PS_ERR_IO, true, "Target CELL.BIASSEC is sepcified by headers, but the number " 769 "of headers doesn't match.\n"); 770 psFree(keywords); 771 return false; 772 } 773 774 psMetadata *header = NULL; // The FITS header 775 if (cell->hdu) { 776 header = cell->hdu->header; 777 } else if (chip->hdu) { 778 header = chip->hdu->header; 779 } else if (fpa->hdu) { 780 header = fpa->hdu->header; 781 } 782 if (! header) { 783 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 784 psFree(keywords); 785 return false; 786 } 787 788 psListIterator *keywordsIter = psListIteratorAlloc(keywords, PS_LIST_HEAD, false); 789 psListIterator *biassecsIter = psListIteratorAlloc(biassecs, PS_LIST_HEAD, false); 790 psString keyword = NULL; // Header keyword from list 791 while ((keyword = psListGetAndIncrement(keywordsIter))) { 792 // Update the header 793 psRegion *biassec = psListGetAndIncrement(biassecsIter); 794 psString biassecString = psRegionToString(*biassec); 795 psMetadataAdd(header, PS_LIST_TAIL, keyword, PS_DATA_STRING | PS_META_REPLACE, "Bias section", 796 biassecString); 797 psFree(biassecString); 798 } 799 psFree(keywordsIter); 800 psFree(biassecsIter); 801 psFree(keywords); 802 803 return true; 804 } 805 806 psError(PS_ERR_IO, true, "CELL.BIASSEC.SOURCE (%s) is not HEADER or VALUE.\n", source); 807 return false; 808 } 809 810 // This function actually does both CELL.XBIN and CELL.YBIN, since if CELL.XBIN and CELL.YBIN are specified by 811 // the same header, we need to check to update them together. 812 bool pmConceptWrite_CELL_XBIN(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 813 { 814 psMetadataItem *xBinItem = psMetadataLookup(cell->concepts, "CELL.XBIN"); // Binning factor in x 815 psMetadataItem *yBinItem = psMetadataLookup(cell->concepts, "CELL.YBIN"); // Binning factor in y 816 817 const psMetadata *camera = fpa->camera; 818 psMetadata *translation = psMetadataLookupMD(NULL, camera, "TRANSLATION"); 819 psString xKeyword = psMetadataLookupStr(NULL, translation, "CELL.XBIN"); 820 psString yKeyword = psMetadataLookupStr(NULL, translation, "CELL.YBIN"); 821 if (strlen(xKeyword) > 0 && strcasecmp(xKeyword, yKeyword) != 0) { 822 pmConceptWriteToHeader(fpa, chip, cell, xBinItem); 823 xBinItem = NULL; 824 } 825 if (strlen(yKeyword) > 0 && strcasecmp(xKeyword, yKeyword) != 0) { 826 pmConceptWriteToHeader(fpa, chip, cell, yBinItem); 827 yBinItem = NULL; 828 } 829 if (strlen(xKeyword) > 0 && strlen(yKeyword) > 0 && strcasecmp(xKeyword, yKeyword) == 0) { 426 psMetadataItem *pmConceptParse_CELL_Positions(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 427 { 428 assert(concept); 429 assert(cameraFormat); 430 431 if (concept->type != PS_TYPE_S32) { 432 psError(PS_ERR_IO, true, "Concept %s is not of type S32, as expected.\n", pattern->name); 433 return NULL; 434 } 435 int offset = concept->data.S32; 436 offset += fortranCorr(cameraFormat, pattern->name); 437 return psMetadataItemAllocS32(pattern->name, pattern->comment, offset); 438 } 439 440 441 442 psMetadataItem *pmConceptFormat_CELL_TRIMSEC(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 443 { 444 assert(concept); 445 446 psRegion *trimsec = concept->data.V; // The trimsec region 447 psString trimsecString = psRegionToString(*trimsec); 448 psMetadataItem *formatted = psMetadataItemAllocStr(trimsecItem->name, trimsecItem->comment, 449 trimsecString); 450 psFree(trimsecString); 451 return formatted; 452 } 453 454 455 bool pmConceptFormat_CELL_BIASSEC(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 456 { 457 psList *biassecs = concept->data.V; // The biassecs region list 458 psString biassecString = NULL; // String containing the biassecs 459 psListIterator *biassecsIter = psListIteratorAlloc(biassecs, PS_LIST_HEAD, false); // Iterator 460 psRegion *region = NULL; // Region from iteration 461 bool first = true; // Are we on the first one? 462 while ((region = psListGetAndIncrement(biassecsIter))) { 463 psString regionString = psRegionToString(*region); // The string region "[x0:x1,y0:y1]" 464 if (first) { 465 psStringAppend(&biassecString, "%s", regionString); 466 first = false; 467 } else { 468 psStringAppend(&biassecString, ";%s", regionString); // Put in a semi-colon 469 } 470 psFree(regionString); 471 } 472 psFree(biassecsIter); 473 psMetadataItem *formatted = psMetadataItemAllocStr(concept->name, concept->comment, biassecString); 474 psFree(biassecString); // Drop reference 475 return formatted; 476 } 477 478 479 // This function actually does both CELL.XBIN and CELL.YBIN if CELL.XBIN and CELL.YBIN are specified by the 480 // same header. 481 psMetadataItem *pmConceptFormat_CELL_XBIN(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 482 { 483 assert(concept); 484 485 psMetadata *translation = psMetadataLookupMD(NULL, cameraFormat, "TRANSLATION"); 486 bool xBinOK = true, yBinOK = true; // Status of MD lookups 487 psString xKeyword = psMetadataLookupStr(&xBinOK, translation, "CELL.XBIN"); 488 psString yKeyword = psMetadataLookupStr(&yBinOK, translation, "CELL.YBIN"); 489 if (xBinOK && yBinOK && strlen(xKeyword) > 0 && strlen(yKeyword) > 0 && 490 strcasecmp(xKeyword, yKeyword) == 0) { 491 psMetadataItem *yBinItem = psMetadataLookup(cell->concepts, "CELL.YBIN"); // Binning factor in y 830 492 psString binString = psStringCopy(""); 831 psStringAppend(&binString, "%d,%d", xBinItem->data.S32, yBinItem->data.S32);832 psMetadataItem *binItem = psMetadataItemAllocStr( xKeyword, "Binning factor in x and y", binString);493 psStringAppend(&binString, "%d,%d", concept->data.S32, yBinItem->data.S32); 494 psMetadataItem *binItem = psMetadataItemAllocStr(concept->name, concept->comment, binString); 833 495 psFree(binString); 834 psMetadata *header = NULL; // The FITS header 835 if (cell->hdu) { 836 header = cell->hdu->header; 837 } else if (chip->hdu) { 838 header = chip->hdu->header; 839 } else if (fpa->hdu) { 840 header = fpa->hdu->header; 841 } 842 if (! header) { 843 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 844 return false; 845 } 846 psMetadataAddItem(header, binItem, PS_LIST_TAIL, PS_META_REPLACE); 847 xBinItem = NULL; 848 yBinItem = NULL; 849 psFree(binItem); 850 } 851 852 // Do it in the usual way if we have to 853 if (xBinItem) { 854 pmConceptWriteItem(fpa, chip, cell, db, xBinItem); 855 } 856 if (yBinItem) { 857 pmConceptWriteItem(fpa, chip, cell, db, yBinItem); 858 } 859 860 return true; 861 } 862 863 // This is a dummy function, since CELL.YBIN is done by CELL.XBIN 864 bool pmConceptWrite_CELL_YBIN(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 865 { 866 return true; 867 } 868 869 870 871 bool pmConceptWrite_CELL_TIMESYS(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 872 { 873 psMetadataItem *sysItem = psMetadataLookup(cell->concepts, "CELL.TIMESYS"); 496 return binItem; 497 } 498 499 // Otherwise, there's no formatting required 500 return concept; 501 } 502 503 // Only need to format if both if CELL.XBIN and CELL.YBIN are not specified by the same header. 504 psMetadataItem *pmConceptFormat_CELL_YBIN(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 505 { 506 assert(concept); 507 508 psMetadata *translation = psMetadataLookupMD(NULL, cameraFormat, "TRANSLATION"); 509 bool xBinOK = true, yBinOK = true; // Status of MD lookups 510 psString xKeyword = psMetadataLookupStr(&xBinOK, translation, "CELL.XBIN"); 511 psString yKeyword = psMetadataLookupStr(&yBinOK, translation, "CELL.YBIN"); 512 if (xBinOK && yBinOK && strlen(xKeyword) > 0 && strlen(yKeyword) > 0 && 513 strcasecmp(xKeyword, yKeyword) == 0) { 514 // Censor this --- it's already done (though no harm if it's done twice 515 return NULL; 516 } 517 518 // No formatting required 519 return concept; 520 } 521 522 523 psMetadataItem *pmConceptFormat_CELL_TIMESYS(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 524 { 874 525 psString sys = NULL; // String to store 875 switch ( sysItem->data.S32) {526 switch (concept->data.S32) { 876 527 case PS_TIME_TAI: 877 528 sys = psStringCopy("TAI"); … … 889 540 sys = psStringCopy("Unknown"); 890 541 } 891 psMetadataItem *newItem = psMetadataItemAllocStr("CELL.TIMESYS", "Time system", sys); 892 bool success = pmConceptWriteItem(fpa, chip, cell, db, newItem); 893 psFree(newItem); 542 psMetadataItem *newItem = psMetadataItemAllocStr(concept->name, concept->comment, sys); 894 543 psFree(sys); 895 544 … … 897 546 } 898 547 899 bool pmConceptWrite_CELL_TIME(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 900 { 901 psMetadataItem *timeItem = psMetadataLookup(cell->concepts, "CELL.TIME"); 902 psTime *time = timeItem->data.V; // The time 903 psString dateTimeString = psTimeToISO(time); // String representation 904 905 psMetadata *formats = psMetadataLookupMD(NULL, fpa->camera, "FORMATS"); 548 psMetadataItem *pmConceptFormat_CELL_TIME(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell) 549 { 550 psTime *time = concept->data.V; // The time 551 psMetadata *formats = psMetadataLookupMD(NULL, cameraFormat, "FORMATS"); 906 552 psString format = psMetadataLookupStr(NULL, formats, "CELL.TIME"); 907 553 908 if (strlen(format) == 0) { 909 // No format specified --> do it in the usual way (maybe it's a DB lookup) 910 psMetadataItem *newTimeItem = psMetadataItemAllocStr("CELL.TIME", "Time of observation", 911 dateTimeString); 912 bool success = pmConceptWriteItem(fpa, chip, cell, db, newTimeItem); 913 psFree(newTimeItem); 554 if (strlen(format) == 0 || strcasecmp(format, "ISO") == 0) { 555 psString dateTimeString = psTimeToISO(time); // String representation 556 psMetadataItem *item = psMetadataItemAllocStr(concept->name, concept->comment, dateTimeString); 914 557 psFree(dateTimeString); 915 return success; 916 } 917 if (strcasecmp(format, "ISO") == 0) { 918 // dateTimeString contains an ISO time 919 psMetadataItem *newTimeItem = psMetadataItemAllocStr("CELL.TIME", "Time of observation", 920 dateTimeString); 921 bool success = pmConceptWriteItem(fpa, chip, cell, db, newTimeItem); 922 psFree(newTimeItem); 558 return item; 559 } 560 if (strstr(format, "SEPARATE")) { 561 // We're working with two separate headers --- construct a list with the date and time separately 562 psString dateTimeString = psTimeToISO(time); // String representation 563 psList *dateTime = psStringSplit(dateTimeString, "T"); 923 564 psFree(dateTimeString); 924 return success; 925 } 926 if (strstr(format, "SEPARATE")) { 927 // We're working with two separate headers 928 psMetadata *header = NULL; // The FITS header 929 if (cell->hdu) { 930 header = cell->hdu->header; 931 } else if (chip->hdu) { 932 header = chip->hdu->header; 933 } else if (fpa->hdu) { 934 header = fpa->hdu->header; 935 } 936 if (! header) { 937 psError(PS_ERR_IO, true, "Unable to find FITS header!\n"); 938 psFree(dateTimeString); 939 return false; 940 } 941 942 // Get the headers 943 const psMetadata *camera = fpa->camera; 944 psMetadata *translation = psMetadataLookupMD(NULL, camera, "TRANSLATION"); 945 psString keywords = psMetadataLookupStr(NULL, translation, "CELL.TIME"); 946 psList *dateTimeKeywords = psStringSplit(keywords, " ,;"); 947 psString dateKeyword = psListGet(dateTimeKeywords, PS_LIST_HEAD); 948 psString timeKeyword = psListGet(dateTimeKeywords, PS_LIST_TAIL); 949 950 psList *dateTime = psStringSplit(dateTimeString, " T"); // Find the middle T 951 psString dateString = psListGet(dateTime, PS_LIST_HEAD); 952 psString timeString = psListGet(dateTime, PS_LIST_TAIL); 953 565 psString dateString = psListGet(dateTime, PS_LIST_HEAD); // The date string 566 psString timeString = psListGet(dateTime, PS_LIST_TAIL); // The time string 567 568 // Need to format the strings.... 954 569 // XXX: Couldn't be bothered doing these right now 955 570 if (strstr(format, "PRE2000")) { 956 571 psError(PS_ERR_IO, true, "Don't you realise it's the twenty-first century?\n"); 957 psFree(dateTimeString);958 // Should free other stuff, but this is work in progress959 572 return false; 960 573 } 961 574 if (strstr(format, "BACKWARDS")) { 962 575 psError(PS_ERR_IO, true, "You want it BACKWARDS? Not right now, thanks.\n"); 963 psFree(dateTimeString);964 // Should free other stuff, but this is work in progress965 576 return false; 966 577 } 967 578 968 bool success = true; 969 psMetadataItem *dateItem = psMetadataItemAllocStr(dateKeyword, "Date of observation", dateString); 970 psMetadataItem *timeItem = psMetadataItemAllocStr(timeKeyword, "Time of observation", timeString); 971 success = psMetadataAddItem(header, dateItem, PS_LIST_TAIL, PS_META_REPLACE) && 972 psMetadataAddItem(header, timeItem, PS_LIST_TAIL, PS_META_REPLACE); 973 974 psFree(dateTimeKeywords); 975 psFree(dateTime); 976 psFree(dateItem); 977 psFree(timeItem); 978 979 return success; 579 psMetadataItem *dateItem = psMetadataItemAllocStr(concept->name, "The date of observation", 580 dateString); 581 psMetadataItem *timeItem = psMetadataItemAllocStr(concept->name, "The time of observation", 582 timeString); 583 psFree(dateString); 584 psFree(timeString); 585 586 psListRemove(dateTime, PS_LIST_HEAD); 587 psListRemove(dateTime, PS_LIST_HEAD); 588 psListAdd(dateTime, PS_LIST_HEAD, dateItem); 589 psListAdd(dateTime, PS_LIST_TAIL, timeItem); 590 591 psMetadataItem *item = psMetadataItemAllocPtr(concept->name, PS_DATA_LIST, concept->comment, 592 dateTime); 593 return item; 980 594 } 981 595 if (strcasecmp(format, "MJD") == 0) { 982 596 double mjd = psTimeToMJD(time); 983 psMetadataItem *newTimeItem = psMetadataItemAllocF64("CELL.TIME", "MJD of observation", mjd); 984 bool success = pmConceptWriteItem(fpa, chip, cell, db, newTimeItem); 985 psFree(newTimeItem); 986 psFree(dateTimeString); 987 return success; 597 return psMetadataItemAllocF64(concept->name, concept->comment, mjd); 988 598 } 989 599 if (strcasecmp(format, "JD") == 0) { 990 600 double jd = psTimeToMJD(time); 991 psMetadataItem *newTimeItem = psMetadataItemAllocF64("CELL.TIME", "JD of observation", jd); 992 bool success = pmConceptWriteItem(fpa, chip, cell, db, newTimeItem); 993 psFree(newTimeItem); 994 psFree(dateTimeString); 995 return success; 996 } 997 998 psError(PS_ERR_IO, true, "Not sure how to write concept CELL.TIME (%s)\n", dateTimeString); 999 return false; 1000 } 1001 1002 bool pmConceptWrite_CELL_X0(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 1003 { 1004 psMetadataItem *x0item = psMetadataLookup(cell->concepts, "CELL.X0"); 1005 psMetadataItem *newItem = psMetadataItemAllocS32("CELL.X0", "Position of (0,0) on the chip", 1006 x0item->data.S32 - fortranCorr(fpa, "CELL.X0")); 1007 return pmConceptWriteItem(fpa, chip, cell, db, newItem); 1008 } 1009 1010 bool pmConceptWrite_CELL_Y0(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db) 1011 { 1012 psMetadataItem *y0item = psMetadataLookup(cell->concepts, "CELL.Y0"); 1013 psMetadataItem *newItem = psMetadataItemAllocS32("CELL.Y0", "Position of (0,0) on the chip", 1014 y0item->data.S32 - fortranCorr(fpa, "CELL.Y0")); 1015 return pmConceptWriteItem(fpa, chip, cell, db, newItem); 1016 } 1017 601 return psMetadataItemAllocF64("CELL.TIME", "JD of observation", jd); 602 } 603 604 psError(PS_ERR_IO, true, "Not sure how to format concept CELL.TIME (%s)\n", dateTimeString); 605 return NULL; 606 } 607 608 psMetadataItem *pmConceptFormat_CELL_Positions(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell *db) 609 { 610 assert(concept); 611 assert(cameraFormat); 612 613 if (concept->type != PS_TYPE_S32) { 614 psError(PS_ERR_IO, true, "Concept %s is not of type S32, as expected.\n", pattern->name); 615 return NULL; 616 } 617 int offset = concept->data.S32; 618 offset -= fortranCorr(cameraFormat, concept->name); 619 return psMetadataItemAllocS32(concept->name, concept->comment, offset); 620 } 621 -
branches/rel10_ifa/psModules/src/astrom/pmConceptsStandard.h
r6448 r6570 5 5 #include "pmFPA.h" 6 6 7 psMetadataItem *pmConceptRead_FPA_RA(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 8 psMetadataItem *pmConceptRead_FPA_DEC(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 9 bool pmConceptWrite_FPA_RA(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 10 bool pmConceptWrite_FPA_DEC(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 11 psMetadataItem *pmConceptRead_CELL_TRIMSEC(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 12 psMetadataItem *pmConceptRead_CELL_BIASSEC(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 13 psMetadataItem *pmConceptRead_CELL_XBIN(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 14 psMetadataItem *pmConceptRead_CELL_YBIN(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 15 psMetadataItem *pmConceptRead_CELL_TIMESYS(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 16 psMetadataItem *pmConceptRead_CELL_TIME(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 17 psMetadataItem *pmConceptRead_CELL_X0(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 18 psMetadataItem *pmConceptRead_CELL_Y0(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 19 bool pmConceptWrite_CELL_TRIMSEC(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 20 bool pmConceptWrite_CELL_BIASSEC(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 21 bool pmConceptWrite_CELL_XBIN(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 22 bool pmConceptWrite_CELL_YBIN(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 23 bool pmConceptWrite_CELL_TIMESYS(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 24 bool pmConceptWrite_CELL_TIME(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 25 bool pmConceptWrite_CELL_X0(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 26 bool pmConceptWrite_CELL_Y0(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db); 7 psMetadataItem *pmConceptParse_FPA_Coords(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell); 8 psMetadataItem *pmConceptFormat_FPA_Coords(psMetadataItem *concept, psMetadataItem *pattern, pmConceptSpec *spec, psMetadata *cameraFormat); 9 psMetadataItem *pmConceptParse_CELL_TRIMSEC(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell); 10 psMetadataItem *pmConceptParse_CELL_BIASSEC(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell); 11 psMetadataItem *pmConceptParse_CELL_BINNING(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell); 12 psMetadataItem *pmConceptParse_CELL_TIMESYS(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell); 13 psMetadataItem *pmConceptParse_CELL_TIME(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell); 14 psMetadataItem *pmConceptParse_CELL_Positions(psMetadataItem *concept, psMetadataItem *pattern, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell); 15 psMetadataItem *pmConceptFormat_CELL_TRIMSEC(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell); 16 bool pmConceptFormat_CELL_BIASSEC(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell); 17 psMetadataItem *pmConceptFormat_CELL_XBIN(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell); 18 psMetadataItem *pmConceptFormat_CELL_YBIN(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell); 19 psMetadataItem *pmConceptFormat_CELL_TIMESYS(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell); 20 psMetadataItem *pmConceptFormat_CELL_TIME(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell); 21 psMetadataItem *pmConceptFormat_CELL_Positions(psMetadataItem *concept, psMetadata *cameraFormat, pmFPA *fpa, pmChip *chip, pmCell *cell *db); 27 22 28 23 #endif -
branches/rel10_ifa/psModules/src/astrom/pmConceptsWrite.c
r6552 r6570 7 7 #include "psAdditionals.h" 8 8 9 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 10 // File-static functions 11 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 9 12 10 13 static bool compareConcepts(psMetadataItem *item1, // First item to compare … … 67 70 } 68 71 72 // Format a single concept 73 static psMetadataItem *conceptFormat(pmConceptSpec *spec, // The concept specification 74 psMetadataItem *concept, // The concept to parse 75 psMetadata *cameraFormat, // The camera format 76 pmFPA *fpa, // The FPA 77 pmChip *chip, // The chip 78 pmCell *cell // The cell 79 ) 80 { 81 if (concept) { 82 psMetadataItem *formatted = NULL; // The formatted concept 83 if (spec->format) { 84 formatted = spec->format(concept, cameraFormat, fpa, chip, cell); 85 } else { 86 formatted = psMemIncrRefCounter(concept); 87 } 88 89 return formatted; 90 } 91 } 92 93 static bool writeHeader(pmHDU *hdu, // HDU for which to add to the header 94 const char *keyword, // Keyword to add 95 psMetadataItem *item // Item to add to the header 96 ) 97 { 98 switch (item->type) { 99 case PS_DATA_STRING: 100 return psMetadataAddStr(hdu->header, PS_LIST_TAIL, keyword, PS_META_REPLACE, item->comment, 101 item->data.V); 102 case PS_DATA_S32: 103 return psMetadataAddS32(hdu->header, PS_LIST_TAIL, keyword, PS_META_REPLACE, item->comment, 104 item->data.S32); 105 case PS_DATA_F32: 106 return psMetadataAddF32(hdu->header, PS_LIST_TAIL, keyword, PS_META_REPLACE, item->comment, 107 item->data.F32); 108 case PS_DATA_F64: 109 return psMetadataAddF64(hdu->header, PS_LIST_TAIL, keyword, PS_META_REPLACE, item->comment, 110 item->data.F64); 111 default: 112 psLogMsg(__func__, PS_LOG_WARN, "Type of %s is not suitable for a FITS header --- not added.\n", 113 item->name); 114 return false; 115 } 116 } 117 118 119 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 120 // Public functions 121 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 122 123 bool pmConceptsWriteToCamera(psMetadata *specs, // The concept specifications 124 pmCell *cell, // The cell 125 psMetadata *concepts // The concepts 126 ) 127 { 128 if (cell) { 129 pmHDU *hdu = getLowestHDU(NULL, NULL, cell); // The HDU at the lowest level 130 psMetadata *cameraFormat = hdu->format; // The camera format 131 psMetadataIterator *specsIter = psMetadataIteratorAlloc(specs, PS_LIST_HEAD, NULL); // Iterator 132 psMetadataItem *specItem = NULL; // Item from the specs metadata 133 while ((specItem = psMetadataGetAndIncrement(specsIter))) { 134 pmConceptSpec *spec = specItem->data.V; // The specification 135 psString name = specItem->name; // The concept name 136 psMetadataItem *cameraItem = psMetadataLookup(cell->config, name); // The concept from the camera, 137 // or NULL 138 if (cameraItem) { 139 // Grab the concept 140 psMetadataItem *conceptItem = psMetadataLookup(concepts, name); // The concept 141 // Formatted version 142 psMetadataItem *formatted = conceptFormat(spec, conceptItem, cameraFormat, NULL, NULL, cell); 143 psString nameSource = NULL; // String with the concept name and ".SOURCE" added 144 psStringAppend(nameSource, "%s.SOURCE", name); 145 bool mdok = true; // Status of MD lookup 146 psString source = psMetadataLookupStr(&mdok, cell->config, nameSource); // The source 147 if (mdok && strlen(source) > 0) { 148 if (strcasecmp(source, "HEADER") == 0) { 149 if (cameraItem->type != PS_DATA_STRING) { 150 psLogMsg(__func__, PS_LOG_WARN, "Concept %s is specified by header, but is not " 151 "of type STR --- ignored.\n", conceptItem->name) 152 continue; 153 } 154 writeHeader(hdu, cameraItem->data.V, formatted); 155 continue; 156 } 157 if (strcasecmp(source, "VALUE") == 0) { 158 if (! compareConcepts(cameraItem, formatted)) { 159 psLogMsg(__func__, PS_LOG_WARN, "Concept %s is specified by value in the camera " 160 "format, but the values don't match.\n"); 161 } 162 continue; 163 } 164 psLogMsg(__func__, PS_LOG_WARN, "Concept source %s isn't HEADER or VALUE --- can't " 165 "write\n", nameSource); 166 continue; 167 } 168 // Assume it's specified by value 169 if (! compareConcepts(cameraItem, formatted)) { 170 psLogMsg(__func__, PS_LOG_WARN, "Concept %s is specified by value in the camera " 171 "format, but the values don't match.\n"); 172 } 173 } 174 175 } 176 psFree(specsIter); 177 return true; 178 } 179 return false; 180 } 181 182 183 bool pmConceptsWriteToDefault(psMetadata *specs, // The concept specifications 184 pmFPA *fpa, // The FPA 185 pmChip *chip, // The chip 186 pmCell *cell, // The cell 187 psMetadata *concepts // The concepts 188 ) 189 { 190 bool mdok = true; // Status of MD lookup 191 psMetadata *defaults = psMetadataLookupMD(&mdok, cameraFormat, "DEFAULTS"); // The DEFAULTS spec 192 if (mdok && defaults) { 193 pmHDU *hdu = getLowestHDU(fpa, chip, cell); // The HDU at the lowest level 194 psMetadata *cameraFormat = hdu->format; // The camera format 195 psMetadataIterator *specsIter = psMetadataIteratorAlloc(specs, PS_LIST_HEAD, NULL); // Iterator 196 psMetadataItem *specItem = NULL; // Item from the specs metadata 197 while ((specItem = psMetadataGetAndIncrement(specsIter))) { 198 pmConceptSpec *spec = specItem->data.V; // The specification 199 psString name = specItem->name; // The concept name 200 psMetadataItem *defaultItem = psMetadataLookup(defaults, name); // The item from the DEFAULTS 201 if (defaultItem) { 202 psMetadataItem *conceptItem = psMetadataLookup(concepts, name); // The item from the concepts 203 psMetadataItem *formatted = conceptFormat(spec, conceptItem, cameraFormat, fpa, chip, cell); 204 if (! compareConcepts(cameraItem, formatted)) { 205 psLogMsg(__func__, PS_LOG_WARN, "Concept %s is specified by the DEFAULTS in the camera " 206 "format, but the values don't match.\n"); 207 } 208 } 209 } 210 psFree(specsIter); 211 return true; 212 } 213 return false; 214 } 215 216 // XXX need to write multiple headers if I get a list 217 bool pmConceptsWriteToHeader(psMetadata *specs, // The concept specifications 218 pmFPA *fpa, // The FPA 219 pmChip *chip, // The chip 220 pmCell *cell, // The cell 221 psMetadata *concepts // The concepts 222 ) 223 { 224 bool mdok = true; // Status of MD lookup 225 psMetadata *translation = psMetadataLookupMD(&mdok, cameraFormat, "TRANSLATION"); // The TRANSLATION spec 226 if (mdok && translation) { 227 pmHDU *hdu = getLowestHDU(fpa, chip, cell); // The HDU at the lowest level 228 psMetadata *cameraFormat = hdu->format; // The camera format 229 psMetadataIterator *specsIter = psMetadataIteratorAlloc(specs, PS_LIST_HEAD, NULL); // Iterator 230 psMetadataItem *specItem = NULL; // Item from the specs metadata 231 while ((specItem = psMetadataGetAndIncrement(specsIter))) { 232 pmConceptSpec *spec = specItem->data.V; // The specification 233 psString name = specItem->name; // The concept name 234 psMetadataItem *headerItem = psMetadataLookup(translation, name); // The item from the TRANSLATION 235 if (headerItem) { 236 if (headerItem->type != PS_DATA_STRING) { 237 psLogMsg(__func__, PS_LOG_WARN, "TRANSLATION keyword for concept %s isn't of type STR ---" 238 " ignored.", name); 239 continue; 240 } 241 psMetadataItem *conceptItem = psMetadataLookup(concepts, name); // The item from the concepts 242 psMetadataItem *formatted = conceptFormat(spec, conceptItem, cameraFormat, fpa, chip, cell); 243 psList *keywords = psStringSplit(headerItem->data.V, " ,;"); // List of header keywords 244 if (formatted->type == PS_DATA_LIST) { 245 psList *values = formatted->data.V; // The values for the headers 246 if (values->n != keywords->n) { 247 psLogMsg(__func__, PS_LOG_WARN, "Number of headers specified does not match number " 248 "of values for concept %s.\n", name); 249 } 250 psListIterator *valuesIter = psListIteratorAlloc(values, PS_LIST_HEAD, false); // Iterator 251 psListIterator *keywordsIter = psListIteratorAlloc(keywords, PS_LIST_HEAD, false); 252 psMetadataItem *valuesItem = NULL; // Item from list 253 while ((valuesItem = psListGetAndIncrement(valuesIter))) { 254 psString keyword = psListGetAndIncrement(keywordsIter); // Keyword from the list 255 if (strlen(keyword) > 0) { 256 writeHeader(hdu, keyword, formatted); 257 } 258 } 259 psFree(valuesIter); 260 psFree(keywordsIter); 261 } else { 262 psString keyword = psListGet(keywords, PS_LIST_HEAD); // The keyword 263 writeHeader(hdu, keyword, formatted); 264 } 265 } 266 } 267 psFree(specsIter); 268 return true; 269 } 270 return false; 271 } 272 273 274 bool pmConceptsWriteToDatabase(psMetadata *specs, // The concept specifications 275 pmFPA *fpa, // The FPA 276 pmChip *chip, // The chip 277 pmCell *cell, // The cell 278 psDB *db,// The database handle 279 psMetadata *concepts // The concepts 280 ) 281 { 282 bool mdok = true; // Status of MD lookup 283 psMetadata *database = psMetadataLookupMD(&mdok, cameraFormat, "DATABASE"); // The DATABASE spec 284 if (mdok && database) { 285 pmHDU *hdu = getLowestHDU(fpa, chip, cell); // The HDU at the lowest level 286 psMetadata *cameraFormat = hdu->format; // The camera format 287 psMetadataIterator *specsIter = psMetadataIteratorAlloc(specs, PS_LIST_HEAD, NULL); // Iterator 288 psMetadataItem *specItem = NULL; // Item from the specs metadata 289 while ((specItem = psMetadataGetAndIncrement(specsIter))) { 290 pmConceptSpec *spec = specItem->data.V; // The specification 291 psString name = specItem->name; // The concept name 292 293 psMetadataItem *dbItem = psMetadataLookup(&mdok, database, name); // The item from the DATABASE 294 if (dbItem) { 295 if (dbItem->type != PS_DATA_METADATA) { 296 psLogMsg(__func__, PS_LOG_WARN, "DATABASE keyword for concept %s isn't of type METADATA " 297 "--- ignored.\n", name); 298 continue; 299 } 300 301 psMetadataItem *conceptItem = psMetadataLookup(concepts, name); // The item from the concepts 302 psMetadataItem *formatted = conceptFormat(spec, conceptItem, cameraFormat, fpa, chip, cell); 303 304 psMetadata *dbLookup = dbItem->data.V; // How to look up the value of interest 305 // Name of the table 306 const char *tableName = psMetadataLookupStr(&mdStatus, dbLookup, "TABLE"); 307 // Name of "where" columns 308 const char *givenCols = psMetadataLookupStr(&mdStatus, dbLookup, "GIVENDBCOL"); 309 // Values for "where" columns 310 const char *givenPS = psMetadataLookupStr(&mdStatus, dbLookup, "GIVENPS"); 311 312 // Now, need to get the "given"s 313 if (strlen(givenCols) || strlen(givenPS)) { 314 psList *cols = psStringSplit(givenCols, ",;"); // List of column names 315 psList *values = psStringSplit(givenPS, ",;"); // List of value names for the columns 316 psMetadata *selection = psMetadataAlloc(); // The stuff to select in the DB 317 if (cols->n != values->n) { 318 psLogMsg(__func__, PS_LOG_WARN, 319 "The GIVENDBCOL and GIVENPS entries for %s do not have " 320 "the same number of entries --- ignored.\n", concept); 321 } else { 322 // Iterators for the lists 323 psListIterator *colsIter = psListIteratorAlloc(cols, PS_LIST_HEAD, false); 324 psListIterator *valuesIter = psListIteratorAlloc(values, PS_LIST_HEAD, false); 325 char *column = NULL; // Name of the column 326 while ((column = psListGetAndIncrement(colsIter))) { 327 char *name = psListGetAndIncrement(valuesIter); // Name for the value 328 if (!strlen(column) || !strlen(name)) { 329 psLogMsg(__func__, PS_LOG_WARN, "One of the columns or value names for %s is " 330 " empty --- ignored.\n", concept); 331 } else { 332 // Search for the value name 333 psMetadataItem *item = pmConceptReadFromHeader(fpa, chip, cell, name); 334 if (! item) { 335 item = pmConceptReadFromDefault(fpa, chip, cell, name); 336 } 337 if (! item) { 338 psLogMsg(__func__, PS_LOG_ERROR, 339 "Unable to find the value name %s for DB " 340 " lookup on %s --- ignored.\n", name, concept); 341 } else { 342 // We need to create a new psMetadataItem. I don't think we can't simply 343 // hack the existing one, since that could conceivably cause memory leaks 344 psMetadataAddItem(selection, formatted, PS_LIST_TAIL, PS_META_REPLACE); 345 psFree(formatted); 346 } 347 } 348 psFree(name); 349 psFree(column); 350 } // Iterating through the columns 351 psFree(colsIter); 352 psFree(valuesIter); 353 354 // Check first to make sure we're only going to touch one row 355 psArray *dbResult = psDBSelectRows(db, tableName, selection, 2); // Lookup result 356 // Note that we use limit=2 in order to test if there are multiple rows returned 357 if (! dbResult || dbResult->n == 0) { 358 psLogMsg(__func__, PS_LOG_WARN, "Unable to find any rows in DB for %s --- " 359 "ignored\n", concept->name); 360 return false; 361 } else { 362 if (dbResult->n > 1) { 363 psLogMsg(__func__, PS_LOG_WARN, "Multiple rows returned in DB lookup for %s " 364 "--- ignored.\n", concept->name); 365 } 366 // Update the DB 367 psMetadata *update = psMetadataAlloc(); 368 psMetadataAddItem(update, concept, PS_LIST_HEAD, 0); 369 psDBUpdateRows(db, tableName, selection, update); 370 psFree(update); 371 return true; 372 } 373 } 374 psFree(cols); 375 psFree(values); 376 } // Doing the "given"s. 377 } 378 } 379 psFree(specsIter); 380 return true; 381 } 382 return false; 383 } 384 385 386 387 388 #if 0 69 389 70 390 // Well, not really "write", but check to make sure it's there and matches … … 368 688 } 369 689 690 #endif
Note:
See TracChangeset
for help on using the changeset viewer.
