NASA Logo
Ocean Color Science Software

ocssw V2022
l1agen_hawkeye.cpp
Go to the documentation of this file.
1 #include <iostream>
2 #include <fstream>
3 #include <sstream>
4 #include <iomanip>
5 #include <vector>
6 
7 #include "hawkeyeUtil.h"
8 #include "HawkeyeDecode.h"
9 #include "nc4utils.h"
10 #include "timeutils.h"
11 
12 #include "l1agen_hawkeye.h"
13 #include "netcdf.h"
14 
15 #define VERSION "1.0.5"
16 
17 // Modification history:
18 // Programmer Organization Date Ver Description of change
19 // ---------- ------------ ---- --- ---------------------
20 // Joel Gales FutureTech 06/16/17 0.10 Original development
21 // Joel Gales FutureTech 05/01/18 0.20 Generate NETCDF4 output
22 // using CDL file
23 // Joel Gales FutureTech 08/02/18 0.30 Process telemetry files
24 // directly to extract HEB &
25 // ADCS data
26 //
27 // Joel Gales FutureTech 09/20/18 0.31 Pass number of S/C records
28 // to createl1
29 // Joel Gales FutureTech 09/27/18 0.40 Fix ADCS/Hawkeye time issues,
30 // Only write ADCS records within
31 // Hawkeye time period. Store
32 // image parameter data as
33 // attributes.
34 // Joel Gales FutureTech 10/23/18 0.50 Change software_version,
35 // fpga_version,
36 // telemetry_counter, overcurrent
37 // fields from ushort to short,
38 // delta_time from uint to int
39 // Joel Gales SAIC 11/01/18 0.60 Fix byte diff bug in
40 // get_packet_from_frame()
41 // uint8_t byte_diff=
42 // frame[2]-ifct;
43 // Joel Gales SAIC 11/06/18 0.70 Find and write all bracketing
44 // ADCS records within telemetry
45 // stream.
46 // Joel Gales SAIC 03/18/19 0.80 Skip navigation output if no
47 // good navigation records.
48 // Joel Gales SAIC 03/25/19 0.85 Fix problem with finder image
49 // output buffer.
50 // Joel Gales SAIC 03/28/19 0.90 Fix code to support 25 finder
51 // images.
52 // Joel Gales SAIC 04/03/19 0.91 Add finder_time and
53 // finder_delta_time fields
54 // Joel Gales SAIC 05/28/19 0.92 Modifiy to read new L0 granule
55 // format.
56 // Joel Gales SAIC 06/19/19 0.93 Initialize instrument
57 // telemetry to fill values
58 // Joel Gales SAIC 07/31/19 0.94 Modify createl1 function
59 // and image/finder reader
60 // to handle non-standard
61 // size output
62 // Joel Gales SAIC 08/01/19 0.95 Exit 110 if "empty" L1A will
63 // be generated
64 // Joel Gales SAIC 10/25/19 0.96 Trap negative dataLen in
65 // getSHpacket() for all cases
66 // Joel Gales SAIC 10/25/19 0.97 Trap zero finder dimensions
67 // Close file and return
68 // Joel Gales SAIC 03/20/20 0.98 Trap buffer overrun in
69 // FindHeader() when writing
70 // finder images
71 // Liang Hong SAIC 10/02/20 0.981 Check image height limit
72 // Liang Hong SAIC 11/09/20 0.982 Exit with band width/height error
73 // Liang Hong SAIC 01/21/21 0.983 Sensor time, bus_telemetry source
74 // data array boundary fix;
75 // HawkeyeDecodeSpectralImage avoid
76 // infinite loop; quit if image height
77 // over MAX;
78 // Liang Hong SAIC 03/22/21 0.993 Second of day refers to image start
79 // date
80 // Liang Hong SAIC 03/31/21 0.994 Added date_created attribute
81 // Liang Hong SAIC 07/01/21 0.995 Continue processe with excess S/P packets
82 // Liang Hong SAIC 07/12/21 0.996 Boundary check for sensor time array
83 // Liang Hong SAIC 08/31/21 0.997 Update band height limit when exceeding
84 // Liang Hong SAIC 09/28/21 0.998 CCD temp. unsigned to signed fix
85 // Liang Hong SAIC 10/11/21 0.999 CCD temp. -2 degC set to invalid
86 // Liang Hong SAIC 10/27/21 1.0.0 re-formatted a few IF statements
87 // Liang Hong SAIC 01/13/22 1.0.1 abnormal finderscope image data handling
88 // Liang Hong SAIC 02/17/22 1.0.2 flag scan time when delta time is 0
89 // Liang Hong SAIC 03/25/22 1.0.3 keep scan time for the 1st line vs 1.0.2
90 // Liang Hong SAIC 04/19/22 1.0.4 fixed false alarm on no finder image
91 // Liang Hong SAIC 04/21/23 1.0.5 fixed missing endtime when deltatime = 0
92 
93 using namespace std;
94 
95 // Note: To get an HEB dump just supply to L0 file on the command line.
96 
97 int main (int argc, char* argv[])
98 {
99 
100  cout << "l1agen_hawkeye " << VERSION << " ("
101  << __DATE__ << " " << __TIME__ << ")" << endl;
102 
103  if ( argc == 1) {
104  cout << endl <<
105  "l1agen_hawkeye " <<
106  "input_l0_filename input_l0_textfilename output_l1a_filename" << endl;
107 
108  return 0;
109  }
110 
111  // Open L0 telemetry file for reading
112  ifstream tlmfile;
113  tlmfile.open( argv[1], ios::binary | ifstream::in);
114 
115 
116  // Open L0 text file
117  istringstream istr;
118  ifstream l0Text;
119  char txtbuf[512];
120  double startHWKTime;
121  double stopHWKTime;
122  bool bImageCrossDay = false;
123  int32_t startyr, startdy, stopyr, stopdy;
124  double startsec, stopsec;
125  uint32_t nSC;
126  if (argc > 2) {
127  l0Text.open( argv[2], ifstream::in);
128  if ( l0Text.fail() != 0) {
129  cout << endl << "L0 Text File: " << argv[2] << " not found." << endl;
130  exit(1);
131  }
132 
133  // Read StartHWKTime/StopHWKTime
134  while( !l0Text.eof()) {
135  size_t found;
136  l0Text.getline( txtbuf, 512);
137  string sValue = txtbuf;
138 
139  found = sValue.find("StartHWKTime");
140  if ( found != string::npos) {
141  found = sValue.find("=");
142  istr.str(sValue.substr(found+1));
143  istr >> startHWKTime;
144  istr.clear();
145  }
146 
147  found = sValue.find( "StopHWKTime");
148  if ( found != string::npos) {
149  found = sValue.find("=");
150  istr.str(sValue.substr(found+1));
151  istr >> stopHWKTime;
152  istr.clear();
153  }
154  }
155 
156  nSC = (uint32_t) (stopHWKTime - startHWKTime) + 2;
157 
158  tepoch2yds(startHWKTime, &startyr, &startdy, &startsec);
159  tepoch2yds(stopHWKTime, &stopyr, &stopdy, &stopsec);
160  if ((stopyr*1000+stopdy)>(startyr*1000+startdy)) bImageCrossDay = true;
161  }
162 
163 
164  // Allocate ADCS data buffer pointer arrays
166  psensor_t *psensor[MAXNPACKETS];
168  propagator_t *propagator[MAXNPACKETS];
169 
170  uint32_t n[4]={0,0,0,0};
171  uint32_t packet_length;
172 
173  // Image data buffer
174  vector<uint8_t> heb_buf;
175 
176  uint8_t **packet = new uint8_t*;
177  uint32_t nImages=0, nFinder=0;
178 
179  // int first = 1;
180  while (1) {
181  int tlmfile_pos = tlmfile.tellg();
182 
183  // int status = get_packet_from_frame( &tlmfile, packet, packet_length,
184  // first);
185 
186  // cout << tlmfile_pos << endl;
187 
188  int status;
189  uint8_t header[6];
190  tlmfile.read( (char *) header, 6);
191 
192  if( tlmfile.eof()) break;
193 
194  int dataLen = header[4]*256 + header[5] - 2;
195  packet_length = 6 + 3 + dataLen;
196  tlmfile.seekg( -6, ios::cur);
197 
198  (*packet) = new uint8_t[packet_length];
199  tlmfile.read( (char *) (*packet), packet_length);
200 
201  // if (status == 1) {
202  //first = 1;
203  // break;
204  //}
205 
206  // Each packet contains a CCSDS 6-byte header followed by a SeaHawk PUS
207  // subheader. The second byte of the subheader indicates the data type:
208 
209  // 253 Hawkeye data
210  // 254 GPS data
211  // 255 ADCS data
212 
213  // The Hawkeye packets are slightly modified versions of the .heb file
214  // blocks. The block start sequence is replaced by the CCSDS header and
215  // the first two bytes of the PUS subheader. The block type is contained
216  // in the third byte of the subheader. Also, the block length field is
217  // now the packet length, which is 7 bytes longer than the CCSDS header
218  // packet length.
219 
220  if ((*packet)[7] == 255) {
221  short psub = (*packet)[8];
222 
223  if (psub == 1) {
224  sensor[n[0]] = new sensor_t;
225  } else if (psub == 2) {
226  psensor[n[1]] = new psensor_t;
227  } else if (psub == 3) {
228  attitude[n[2]] = new attitude_t;
229  } else if (psub == 4) {
230  propagator[n[3]] = new propagator_t;
231  }
232 
233  // Ver 0.995
234  if (n[psub-1] >= MAXNPACKETS-1) {
235  cout << "Insufficient pointer allocation for psub: " << psub << endl;
236  cout << "Increase value of MAXNPACKETS" << endl;
237  continue;
238  }
239 
240  status = unpack_seahawk_adcs( *packet, startHWKTime, stopHWKTime,
241  sensor[n[0]], psensor[n[1]],
242  attitude[n[2]], propagator[n[3]]);
243 
244  if (status == 0) n[psub-1]++;
245 
246  //if (n[psub-1] == MAXNPACKETS) {
247  // cout << "Insufficient pointer allocation for psub: " << psub << endl;
248  // cout << "Increase value of MAXNPACKETS" << endl;
249  // exit(1);
250  //}
251 
252  } else if ((*packet)[7] == 253) {
253  // HEB data
254  uint16_t row;
255 
256  // Compressed Image/Finder Data
257  if ( (*packet)[8] == 2) {
258  uint8_t infoByte = (*packet)[15];
259  uint8_t sb = infoByte & 0x1f;
260 
261  // sd_f: 0 - finder, 1 - spectral (image)
262  uint8_t sd_f = (infoByte & 0x40) >> 6;
263  uint8_t dark = (infoByte & 0x80) >> 7;
264  memcpy(&row, &(*packet)[20], 2);
265  row = SWAP_2(row);
266 
267  if (sd_f == 0 && sb > nFinder) nFinder = sb;
268  if (sd_f == 1 && sb > nImages) nImages = sb;
269 
270  if ( argc == 2) {
271  cout << "SB or Finder #: " << (int) sb <<
272  " SpecData or Finder: " << (int) sd_f <<
273  " Dark: " << (int) dark << " Row #: " << row <<
274  " packet length: " << packet_length <<
275  " tlmfile_pos: " << tlmfile_pos << endl;
276  }
277  }
278 
279  // Image Parameters Data Block
280  if ( (*packet)[8] == 3) {
281  //cout << "Image Parameter" << endl;
282  uint16_t hgt;
283  memcpy(&hgt, &(*packet)[48], 2);
284  // uint8_t nFinder = (*packet)[55];
285  //cout << "SB hgt: " << SWAP_2(hgt) <<
286  // " # find img: " << (int) nFinder << endl;
287  }
288  //if ( (*packet)[8] == 4) cout << "Telemetry" << endl;
289  // if ( (*packet)[8] == 6) cout << "Mission Log" << endl;
290 
291 
292  // Block start sequence
293  uint8_t bss[6] = {0x00,0x00,0xff,0xff,0xff,0xff};
294 
295  // Compute new checksum
296  uint16_t checksum = 4*255;
297  for (size_t i=8; i<packet_length; i++) {
298  checksum += (*packet)[i];
299  }
300  uint16_t swapcheck = SWAP_2(checksum);
301 
302  // Write HEB data
303  heb_buf.insert(heb_buf.end(), bss, bss+6);
304  heb_buf.insert(heb_buf.end(), &(*packet)[8], &(*packet)[packet_length]);
305  heb_buf.push_back(swapcheck & 0x00ff);
306  heb_buf.push_back((swapcheck & 0xff00) >> 8);
307  } else {
308  // cout << (int) (*packet)[7] << " " << (int) (*packet)[8] << endl;
309 
310  }
311  delete[] (*packet);
312  }
313  uint32_t hebBufLength = heb_buf.size();
314 
315  cout << "Number of SENSOR packets: " << n[SENSOR] << endl;
316  cout << "Number of PSENSOR packets: " << n[PSENSOR] << endl;
317  cout << "Number of ATTITUDE packets: " << n[ATTITUDE] << endl;
318  cout << "Number of PROPAGATOR packets: " << n[PROPAGATOR] << endl << endl;
319 
320  cout << "Number of Spectral Images: " << nImages << endl;
321  cout << "Number of Finder Images: " << nFinder << endl << endl;
322 
323  if ( argc == 2) {
324  ofstream hebFile ("heb_buf.bin", ios::out | ios::binary);
325  hebFile.write((char *) heb_buf.data(), hebBufLength);
326  hebFile.close();
327 
328  return 0;
329  }
330 
331  HawkeyeStreamInfo streamInfo;
332  string l1a_name;
333  l1a_name.assign( argv[3]);
334 
335  // Image height is determined by counting the number of "good" rows
336  // Image width is determined in ScanRow() (for each row which are identical)
337  HawkeyeScanStream( (uint8_t*) heb_buf.data(), hebBufLength, &streamInfo);
338 
339  // Bail if empty
340  if ( streamInfo.spectralInfo[0].width == 0) {
341  cout << "Empty output file: " << l1a_name.c_str() << endl;
342  exit(110);
343  }
344 
345  // check image height not to exceed max value in case of corrupted bytes in raw data reading
346  // LH, 1/21/2021
347  // updated band height checking, LH, 8/31/2021
348  uint16_t band_max_height = 0;
349  for (size_t i=0; i<8; i++) {
350  if (streamInfo.spectralInfo[i].height>band_max_height && streamInfo.spectralInfo[i].height<=MAXIMGHEIGHT) {
351  band_max_height = streamInfo.spectralInfo[i].height;
352  }
353  }
354  if (band_max_height==0) {
355  cout << "Image height in all bands exceeds MAXIMGHEIGHT " << endl;
356  //cout << "Empty output file: " << l1a_name.c_str() << endl;
357  //exit(110);
358  band_max_height = MAXIMGHEIGHT;
359  }
360  for (size_t i=0; i<8; i++) {
361  if (streamInfo.spectralInfo[i].height>MAXIMGHEIGHT) {
362  cout << "Image height " <<streamInfo.spectralInfo[i].height<<" in band " <<(i+1)<< " exceeds MAXIMGHEIGHT " << endl;
363  streamInfo.spectralInfo[i].height = band_max_height;
364  }
365  }
366 
367  // Full size: 18 byte offset / 2 byte time code and 16 bytes dark pixels
368  // Half size: 12 byte offset / 2 byte time code and 10 bytes dark pixels
369  uint32_t rowOffset;
370  if ( streamInfo.spectralInfo[0].width == 1816) rowOffset = 18;
371  if ( streamInfo.spectralInfo[0].width == 908) rowOffset = 10;
372 
373  static l1aFile outfile;
374  outfile.createl1( (char *) l1a_name.c_str(), nSC,
375  streamInfo.spectralInfo[0].width+2-rowOffset,
376  streamInfo.spectralInfo[0].height,
377  streamInfo.finderscopeInfo[0].width,
378  streamInfo.finderscopeInfo[0].height);
379 
380  // scan_line_attributes
381  // parameters_telemetry_data
382  // navigation_data
383  // earth_view_data
384 
385  char buf[32];
386  strcpy( buf, unix2isodate(now(), 'G'));
387 
388  int status;
389  int varid;
390  string varname;
391 
392 
394  int dimid;
395  size_t nTlmBlocks, sizeTelBlk, nCCDtemps, nFPGAvolts, nCurrents, nCCDvolts;
396 
397  nc_inq_dimid( outfile.ncid, "number_of_tlm_blocks", &dimid);
398  nc_inq_dimlen( outfile.ncid, dimid, &nTlmBlocks);
399 
400  nc_inq_dimid( outfile.ncid, "telemetry_block", &dimid);
401  nc_inq_dimlen( outfile.ncid, dimid, &sizeTelBlk);
402 
403  nc_inq_dimid( outfile.ncid, "ccd_temps", &dimid);
404  nc_inq_dimlen( outfile.ncid, dimid, &nCCDtemps);
405 
406  nc_inq_dimid( outfile.ncid, "ccd_volts", &dimid);
407  nc_inq_dimlen( outfile.ncid, dimid, &nCCDvolts);
408 
409  nc_inq_dimid( outfile.ncid, "fpga_volts", &dimid);
410  nc_inq_dimlen( outfile.ncid, dimid, &nFPGAvolts);
411 
412  nc_inq_dimid( outfile.ncid, "currents", &dimid);
413  nc_inq_dimlen( outfile.ncid, dimid, &nCurrents);
414 
415 
416  uint16_t *telemetry = new uint16_t[nTlmBlocks*sizeTelBlk];
417  double *tlm_time = new double[nTlmBlocks];
418  uint32_t *tlm_time_stamp = new uint32_t[nTlmBlocks];
419  int16_t *software_version = new int16_t[nTlmBlocks];
420  int16_t *fpga_version = new int16_t[nTlmBlocks];
421  int16_t *telemetry_counter = new int16_t[nTlmBlocks];
422 
423  float *ccd_temperatures = new float[nTlmBlocks*nCCDtemps];
424  for (size_t i=0; i<nTlmBlocks*nCCDtemps; i++) ccd_temperatures[i] = -999.0;
425 
426  float *fpga_temperature = new float[nTlmBlocks];
427  for (size_t i=0; i<nTlmBlocks; i++) fpga_temperature[i] = -999.0;
428 
429  float *fpga_voltages = new float [nTlmBlocks*nFPGAvolts];
430  for (size_t i=0; i<nTlmBlocks*nFPGAvolts; i++) fpga_voltages[i] = -999.0;
431 
432  int16_t *overcurrent = new int16_t[nTlmBlocks];
433 
434  float *current_monitors = new float[nTlmBlocks*nCurrents];
435  for (size_t i=0; i<nTlmBlocks*nCurrents; i++) current_monitors[i] = -999.0;
436 
437  float *ccd_voltages = new float[nTlmBlocks*nCCDvolts];
438  for (size_t i=0; i<nTlmBlocks*nCCDvolts; i++) ccd_voltages[i] = -999.0;
439 
440  float *solenoid_voltage = new float[nTlmBlocks];
441  for (size_t i=0; i<nTlmBlocks; i++) solenoid_voltage[i] = -999.0;
442 
443  int32_t iyr, idy;
444  double sec;
445 
446  for (size_t i=0; i<nTlmBlocks; i++) {
447  // cout << "i: " << i << endl;
448  tlm_time_stamp[i] = streamInfo.telemetryInfo[i].timeStamp;
449 
450  tlm_time[i] = (streamInfo.imageInfo.epochT0 + tlm_time_stamp[i]) * 0.001;
451 
452  // JD 2015/01/01 = 2457023.5
453  // JD 1980/01/06 = 2444244.5
454  // delta sec = (2457023.5-2444244.5) * 24 * 3600 = 1104105600
455  // Add 16 leapsecs between 1980/01/06 and 2015/01/01
456  // Convert to milliseconds: 1104105616000
457  // Subtract 2^40 = 1099511627776
458  // delta = 4593988224
459  // Convert to days: 4593988224 / (24*3600*1000) = 53.17116
460  // 0.17116 * 24 * 3600 = 14788.224;
461 
462  tlm_time[i] -= (53*24*3600 + 14788.224);
463  tepoch2yds( tlm_time[i], &iyr, &idy, &sec);
464 
465  tlm_time[i] = sec;
466  // if image spans two days
467  if (bImageCrossDay && (sec<80000)) tlm_time[i] = sec+86400.0;
468 
469  memcpy( &telemetry[i*sizeTelBlk], &streamInfo.telemetryInfo[i].telemetry,
470  sizeTelBlk*sizeof(short));
471 
472  uint32_t nChannels = streamInfo.telemetryInfo[i].noChannels;
473  for (size_t j=0; j<nChannels; j++) {
474  uint16_t value =
476 
477  uint16_t interp =
479 
480  switch (j) {
481 
482  case TC_SOFTWARE_VERSION:
483  if ( interp == 1)
485  else
486  software_version[i] = -999;
487  break;
488 
489  case TC_FPGA_VERSION:
490  if ( interp == 1)
491  fpga_version[i] = value;
492  else
493  fpga_version[i] = -999;
494  break;
495 
496  case TC_INDEX:
497  if ( interp == 1)
498  telemetry_counter[i] = value;
499  else
500  telemetry_counter[i] = -999;
501  break;
502 
503  case TC_CCD1_TEMP:
504  case TC_CCD2_TEMP:
505  case TC_CCD3_TEMP:
506  case TC_CCD4_TEMP:
507  if ( interp == 1) {
508  // ver 0.998: CCD temperatures are signed values but read as unsigned. LH
509  ccd_temperatures[i*nCCDtemps+(j-TC_CCD1_TEMP)] = (value<32768)? (value / 32.0):(value / 32.0-2048);
510  }
511  if (i*nCCDtemps+(j-TC_CCD1_TEMP)>0) { // ver 0.999: -2 degC readings following an invalid value are flagged as invalid
512  if ((ccd_temperatures[i*nCCDtemps+(j-TC_CCD1_TEMP)-1]==-999.0) && (ccd_temperatures[i*nCCDtemps+(j-TC_CCD1_TEMP)]==-2.0)) {
513  ccd_temperatures[i*nCCDtemps+(j-TC_CCD1_TEMP)] = -999.0;
514  }
515  }
516  else
517  ccd_temperatures[i*nCCDtemps+(j-TC_CCD1_TEMP)] = -999.0;
518  break;
519 
520  case TC_FPGA_TEMP:
521  if ( interp == 1)
522  fpga_temperature[i] = (float) value;
523  else
524  fpga_temperature[i] = -999.0;
525  break;
526 
527  case TC_FPGA_VAUX:
528  case TC_FPGA_VINT:
529  case TC_FPGA_VNVP:
530  if ( interp == 1)
531  fpga_voltages[i*nFPGAvolts+(j-TC_FPGA_VAUX)] = value / 1000.0;
532  else
533  fpga_voltages[i*nFPGAvolts+(j-TC_FPGA_VAUX)] = -999.0;
534  break;
535 
536  case TC_CCD_VDD_OC:
537  if ( interp == 1)
538  overcurrent[i] = value;
539  else
540  overcurrent[i] = -999;
541  break;
542 
543  case TC_AD7490_CH01:
544  case TC_AD7490_CH02:
545  case TC_AD7490_CH03:
546  case TC_AD7490_CH04:
547  if ( interp == 1)
548  current_monitors[i*nCurrents+(j-TC_AD7490_CH01)] = value / 100.0;
549  else
550  current_monitors[i*nCurrents+(j-TC_AD7490_CH01)] = -999.0;
551  break;
552 
553  case TC_AD7490_CH05:
554  case TC_AD7490_CH06:
555  case TC_AD7490_CH07:
556  case TC_AD7490_CH08:
557  case TC_AD7490_CH09:
558  case TC_AD7490_CH10:
559  case TC_AD7490_CH11:
560  case TC_AD7490_CH12:
561  case TC_AD7490_CH13:
562  case TC_AD7490_CH14:
563  case TC_AD7490_CH15:
564  if ( interp == 1)
565  ccd_voltages[i*nCCDvolts+(j-TC_AD7490_CH05)] = value / 1000.0;
566  else
567  ccd_voltages[i*nCCDvolts+(j-TC_AD7490_CH05)] = -999.0;
568  break;
569 
570  case TC_AD7490_CH16:
571  if ( interp == 1)
572  solenoid_voltage[i] = value / 1000.0;
573  else
574  solenoid_voltage[i] = -999.0;
575  }
576  } // channel loop
577 
578  } // tlm block loop
579 
580 
581  varname.assign( "telemetry");
582  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
583  status = nc_put_var_ushort( outfile.gid[1], varid, telemetry);
584  check_err(status,__LINE__,__FILE__);
585 
586  varname.assign( "tlm_time_stamp");
587  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
588  status = nc_put_var_uint( outfile.gid[1], varid, tlm_time_stamp);
589  check_err(status,__LINE__,__FILE__);
590 
591  varname.assign( "tlm_time");
592  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
593  status = nc_put_var_double( outfile.gid[1], varid, tlm_time);
594  check_err(status,__LINE__,__FILE__);
595 
596  varname.assign( "software_version");
597  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
598  status = nc_put_var_short( outfile.gid[1], varid, software_version);
599  check_err(status,__LINE__,__FILE__);
600 
601  varname.assign( "FPGA_version");
602  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
603  status = nc_put_var_short( outfile.gid[1], varid, fpga_version);
604  check_err(status,__LINE__,__FILE__);
605 
606  varname.assign( "telemetry_counter");
607  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
608  status = nc_put_var_short( outfile.gid[1], varid, telemetry_counter);
609  check_err(status,__LINE__,__FILE__);
610 
611  varname.assign( "CCD_temperatures");
612  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
613  status = nc_put_var_float( outfile.gid[1], varid, ccd_temperatures);
614  check_err(status,__LINE__,__FILE__);
615 
616  varname.assign( "FPGA_temperature");
617  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
618  status = nc_put_var_float( outfile.gid[1], varid, fpga_temperature);
619  check_err(status,__LINE__,__FILE__);
620 
621  varname.assign( "FPGA_voltages");
622  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
623  status = nc_put_var_float( outfile.gid[1], varid, fpga_voltages);
624  check_err(status,__LINE__,__FILE__);
625 
626  varname.assign( "overcurrent");
627  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
628  status = nc_put_var_short( outfile.gid[1], varid, overcurrent);
629  check_err(status,__LINE__,__FILE__);
630 
631  varname.assign( "current_monitors");
632  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
633  status = nc_put_var_float( outfile.gid[1], varid, current_monitors);
634  check_err(status,__LINE__,__FILE__);
635 
636  varname.assign( "CCD_voltages");
637  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
638  status = nc_put_var_float( outfile.gid[1], varid, ccd_voltages);
639  check_err(status,__LINE__,__FILE__);
640 
641  varname.assign( "solenoid_voltage");
642  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
643  status = nc_put_var_float( outfile.gid[1], varid, solenoid_voltage);
644  check_err(status,__LINE__,__FILE__);
645 
646  // Write image paramter data as attributes
647  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "errorCode",
648  NC_USHORT, 1, &streamInfo.imageInfo.errorCode);
649  check_err(status,__LINE__,__FILE__);
650 
651  status = nc_put_att_uint( outfile.gid[1], NC_GLOBAL, "exposureID",
652  NC_UINT, 1, &streamInfo.imageInfo.exposureID);
653  check_err(status,__LINE__,__FILE__);
654 
655  status = nc_put_att_uint( outfile.gid[1], NC_GLOBAL, "imageID",
656  NC_UINT, 1, &streamInfo.imageInfo.imageID);
657  check_err(status,__LINE__,__FILE__);
658 
659  status = nc_put_att_ulonglong( outfile.gid[1], NC_GLOBAL, "epochT0",
660  NC_UINT64, 1, (const long long unsigned int*)
661  &streamInfo.imageInfo.epochT0);
662  check_err(status,__LINE__,__FILE__);
663 
664  status = nc_put_att_uint( outfile.gid[1], NC_GLOBAL, "hostDeltaEpoch",
665  NC_UINT, 1, &streamInfo.imageInfo.hostDeltaEpoch);
666  check_err(status,__LINE__,__FILE__);
667 
668  status = nc_put_att_uint( outfile.gid[1], NC_GLOBAL, "hawkeyeDeltaEpoch",
669  NC_UINT, 1,
670  &streamInfo.imageInfo.hawkeyeDeltaEpoch);
671  check_err(status,__LINE__,__FILE__);
672 
673  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "spectralBinning",
674  NC_USHORT, 1,
675  &streamInfo.imageInfo.spectralBinning);
676  check_err(status,__LINE__,__FILE__);
677 
678  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "finderscopeBinning",
679  NC_USHORT, 1,
680  &streamInfo.imageInfo.finderscopeBinning);
681  check_err(status,__LINE__,__FILE__);
682 
683  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "channelBitfield",
684  NC_USHORT, 1,
685  &streamInfo.imageInfo.channelBitfield);
686  check_err(status,__LINE__,__FILE__);
687 
688  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "ccd1Exposure",
689  NC_USHORT, 1, &streamInfo.imageInfo.ccd1Exposure);
690  check_err(status,__LINE__,__FILE__);
691 
692  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "ccd2Exposure",
693  NC_USHORT, 1, &streamInfo.imageInfo.ccd2Exposure);
694  check_err(status,__LINE__,__FILE__);
695 
696  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "ccd3Exposure",
697  NC_USHORT, 1, &streamInfo.imageInfo.ccd3Exposure);
698  check_err(status,__LINE__,__FILE__);
699 
700  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "ccd4Exposure",
701  NC_USHORT, 1, &streamInfo.imageInfo.ccd4Exposure);
702  check_err(status,__LINE__,__FILE__);
703 
704  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "height",
705  NC_USHORT, 1, &streamInfo.imageInfo.height);
706  check_err(status,__LINE__,__FILE__);
707 
708  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "darkHeight",
709  NC_USHORT, 1, &streamInfo.imageInfo.darkHeight);
710  check_err(status,__LINE__,__FILE__);
711 
712  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "interval",
713  NC_USHORT, 1, &streamInfo.imageInfo.interval);
714  check_err(status,__LINE__,__FILE__);
715 
716  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "oversampling",
717  NC_USHORT, 1, &streamInfo.imageInfo.oversampling);
718  check_err(status,__LINE__,__FILE__);
719 
720  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "finderscopeExposure",
721  NC_USHORT, 1,
722  &streamInfo.imageInfo.finderscopeExposure);
723  check_err(status,__LINE__,__FILE__);
724 
725  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "noFinderscopeImages",
726  NC_USHORT, 1,
727  &streamInfo.imageInfo.noFinderscopeImages);
728  check_err(status,__LINE__,__FILE__);
729 
730  status = nc_put_att_ubyte( outfile.gid[1], NC_GLOBAL, "compression",
731  NC_UBYTE, 1,
732  (uint8_t *) &streamInfo.imageInfo.compression);
733  check_err(status,__LINE__,__FILE__);
734 
735  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "darkSubtracted",
736  NC_USHORT, 1,
737  &streamInfo.imageInfo.darkSubtracted);
738  check_err(status,__LINE__,__FILE__);
739 
740  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "shutterSolenoid",
741  NC_USHORT, 1,
742  &streamInfo.imageInfo.shutterSolenoid);
743  check_err(status,__LINE__,__FILE__);
744 
745  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "readoutOrder",
746  NC_USHORT, 1, &streamInfo.imageInfo.readoutOrder);
747  check_err(status,__LINE__,__FILE__);
748 
749  delete[] ( telemetry);
750  delete[] ( tlm_time);
751  delete[] ( tlm_time_stamp);
752  delete[] ( software_version);
753  delete[] ( fpga_version);
754  delete[] ( telemetry_counter);
755  delete[] ( ccd_temperatures);
756  delete[] ( fpga_temperature);
757  delete[] ( fpga_voltages);
758  delete[] ( overcurrent);
759  delete[] ( current_monitors);
760  delete[] ( ccd_voltages);
761  delete[] ( solenoid_voltage);
762 
763  // Date created
764  strcpy( buf, unix2isodate(now(), 'G'));
765  status = nc_put_att_text(outfile.ncid, NC_GLOBAL,
766  "date_created", strlen(buf), buf);
767 
769  double scan_time[MAXIMGHEIGHT];
770  int32_t delta_time[MAXIMGHEIGHT];
771  for (size_t i=0; i<MAXIMGHEIGHT; i++) {
772  scan_time[i] = -999;
773  delta_time[i] = -999;
774  }
775 
776  int varidDark;
777  size_t startDark[3]={0, 0, 0};
778  size_t countDark[3]={1, 1, (size_t) rowOffset-2};
779  status = nc_inq_varid( outfile.gid[3], "band_dark_pixels", &varidDark);
780 
781  for (size_t i=0; i<8; i++) {
782  startDark[0] = i;
783 
784  int hasAverageDark = streamInfo.spectralInfo[i].averageDarkRowPresent;
785 
786  uint16_t imgHeight = streamInfo.spectralInfo[i].height + hasAverageDark;
787 
788  uint16_t imgWidth = 2 + streamInfo.spectralInfo[i].width;
789  uint64_t epochT0 = streamInfo.imageInfo.epochT0;
790  uint32_t pixelLen = imgHeight * imgWidth;
791 
792  // cout << epochT0 << endl;
793 
794  // uint32_t exposure;
795  //if (i / 2 == 0)
796  //exposure = streamInfo.imageInfo.ccd1Exposure * BAND_US_PER_EXPOSURE_COUNT;
797  //else if (i / 2 == 1)
798  //exposure = streamInfo.imageInfo.ccd2Exposure * BAND_US_PER_EXPOSURE_COUNT;
799  //else if (i / 2 == 2)
800  //exposure = streamInfo.imageInfo.ccd3Exposure * BAND_US_PER_EXPOSURE_COUNT;
801  //else
802  //exposure = streamInfo.imageInfo.ccd4Exposure * BAND_US_PER_EXPOSURE_COUNT;
803 
804  uint16_t *pixels = new uint16_t[pixelLen];
805  for ( size_t j=0; j<pixelLen; j++) pixels[j] = 0;
806 
807  HawkeyeDecodeSpectralImage( i, pixels, pixelLen-imgWidth,
808  NULL, imgWidth);
809 
810  size_t start[2]={0, 0};
811  size_t count[2]={1, (size_t) imgWidth-rowOffset};
812 
813  stringstream varstr;
814  varstr << "band_" << setw(1) << i+1;
815  status = nc_inq_varid( outfile.gid[3], varstr.str().c_str(), &varid);
816 
817  cout << "Writing Band: " << (i+1);
818  cout << " Image size: " << imgWidth-rowOffset << " by "
819  << streamInfo.spectralInfo[i].height << endl;
820 
821  // skip band with invalid width read from corrupted raw data, LH, 11/02/2020
822  if (imgWidth>2000) { // normal image width = 1818
823  cout << "Image Width Error in Band " << (i+1) << endl;
824  exit(101);
825  }
826 
827  // Note: Dark row is not written to L1A file
828  for ( size_t j=0; j < (size_t) (imgHeight-1); j++) {
829  if (i == 0) {
830  delta_time[j] = pixels[j*imgWidth]*256*256 + pixels[j*imgWidth+1];
831  if ((delta_time[j]==0) && (j>0) ) continue; // Flagging scan_time if delta_time is 0, LH, 02/17/2022 ; avoid skipping first record, to get time_coverage_start value, LH 3/25/2022
832  scan_time[j] = epochT0 + delta_time[j];
833  scan_time[j] *= 0.001;
834  scan_time[j] -= (53*24*3600 + 14788.224);
835  tepoch2yds( scan_time[j], &iyr, &idy, &sec);
836  scan_time[j] = sec;
837  if (bImageCrossDay && (sec<80000)) scan_time[j] = sec + 86400.0;
838  if (j == 0) {
839  int16_t year, doy;
840  year = iyr;
841  doy = idy;
842  double myUnixTime= yds2unix(year, doy, sec);
843  strcpy( buf, unix2isodate(myUnixTime, 'G'));
844  status = nc_put_att_text(outfile.ncid, NC_GLOBAL,
845  "time_coverage_start", strlen(buf), buf);
846  }
847  }
848 
849  start[0] = j;
850  status = nc_put_vara_ushort( outfile.gid[3], varid, start, count,
851  &pixels[rowOffset+j*imgWidth]);
852  check_err(status,__LINE__,__FILE__);
853 
854  startDark[1] = j;
855  status = nc_put_vara_ushort( outfile.gid[3], varidDark,
856  startDark, countDark,
857  &pixels[2+j*imgWidth]);
858  check_err(status,__LINE__,__FILE__);
859  }
860 
861  int16_t year, doy;
862  year = iyr;
863  doy = idy;
864  double myUnixTime= yds2unix(year, doy, sec);
865  strcpy( buf, unix2isodate(myUnixTime, 'G'));
866  status = nc_put_att_text(outfile.ncid, NC_GLOBAL,
867  "time_coverage_end", strlen(buf), buf);
868 
869  delete[] pixels;
870  } // Band loop
871 
872  varname.assign( "scan_time");
873  status = nc_inq_varid( outfile.gid[0], varname.c_str(), &varid);
874  status = nc_put_var_double( outfile.gid[0], varid, scan_time);
875  check_err(status,__LINE__,__FILE__);
876 
877  varname.assign( "delta_time");
878  status = nc_inq_varid( outfile.gid[0], varname.c_str(), &varid);
879  status = nc_put_var_int( outfile.gid[0], varid, delta_time);
880  check_err(status,__LINE__,__FILE__);
881 
882 
884  //uint16_t finderHeight = FINDERSCOPE_LIGHT_HEIGHT;
885  //uint16_t finderWidth = FINDERSCOPE_LIGHT_WIDTH;
886 
887  uint16_t finderHeight = 0; // streamInfo.finderscopeInfo[0].height; // ver 1.0.1
888  uint16_t finderWidth = 0; // streamInfo.finderscopeInfo[0].width;
889  // find max height and width of finderscope images [MAX_FINDERSCOPE_IMAGES]
890  for (size_t i=0; i<FINDERSCOPE_MAX_IMAGES; i++) {
891  if (streamInfo.finderscopeInfo[i].height > 0) finderHeight = 480;
892  if (streamInfo.finderscopeInfo[i].width > 0) finderWidth = 756;
893  }
894  uint32_t finderPixelLen = finderHeight*finderWidth;
895 
896  if ( finderPixelLen == 0) {
897  cout << "Zero Finder Pixel Length" << endl;
898  outfile.close();
899  return 0;
900  }
901 
902  uint16_t *finderPixels = new uint16_t[finderPixelLen];
903  for (size_t i=0; i<finderPixelLen; i++) finderPixels[i] = 0;
904 
905  size_t start[3]={0, 0, 0};
906  size_t count[3]={1, finderHeight, finderWidth};
907 
908  double finder_time[FINDERSCOPE_MAX_IMAGES];
909  int32_t finder_delta_time[FINDERSCOPE_MAX_IMAGES];
910  uint64_t epochT0 = streamInfo.imageInfo.epochT0;
911 
912  status = nc_inq_varid( outfile.gid[3], "finder", &varid);
913 
914  cout << endl << "Writing Finder Images";
915  cout << " Finder size: " << finderWidth << " by " << finderHeight << endl;
916  int finderScopeStatus;
917  // for (size_t i=0; i< (size_t) streamInfo.noFinderscopeImages; i++) {
918  // There are abnormal cases when finder scope images are stored in sequence as,
919  // [5,6,7,8,9,10,11,15,16,17,18,19,2]
920  for (size_t i=0; i< FINDERSCOPE_MAX_IMAGES; i++) {
921  finder_time[i] = -999;
922  if (streamInfo.finderscopeInfo[i].width==0) continue;
923 
924  finderScopeStatus =
925  HawkeyeDecodeFinderscopeImage(i, finderPixels, finderPixelLen);
926 
927  // if ( finderScopeStatus == HSE_NO_HEADER_FOUND) break;
928  if ( finderScopeStatus == HSE_NO_HEADER_FOUND) continue;
929 
930  // We consolidate the finderPixels buffer by removing the first
931  // n dark pixels from each row and then zeroing out the remaining rows.
932 
933  // for (size_t j=0; j<(752*480/756); j++) {
934  // memmove(&finderPixels[j*FINDERSCOPE_LIGHT_WIDTH],
935  // &finderPixels[j*(FINDERSCOPE_LIGHT_WIDTH+4)+4],
936  // FINDERSCOPE_LIGHT_WIDTH*2);
937  //}
938  //memset(&finderPixels[(752*480/756)*FINDERSCOPE_LIGHT_WIDTH],
939  // 0, (finderPixelLen-(752*480/756)*FINDERSCOPE_LIGHT_WIDTH)*2);
940 
941  start[0] = i;
942  status = nc_put_vara_ushort( outfile.gid[3], varid, start, count,
943  finderPixels);
944  check_err(status,__LINE__,__FILE__);
945 
946  finder_delta_time[i] = streamInfo.finderscopeInfo[i].timeStamp;
947  finder_time[i] = epochT0 + finder_delta_time[i];
948  finder_time[i] *= 0.001;
949  finder_time[i] -= (53*24*3600 + 14788.224);
950  tepoch2yds( finder_time[i], &iyr, &idy, &sec);
951  finder_time[i] = sec;
952  if (bImageCrossDay && (sec<80000)) finder_time[i] = sec + 86400.0;
953 
954  }
955  delete[] finderPixels;
956 
957  if ( finderScopeStatus == HSE_NO_ERROR) {
958  varname.assign( "finder_time");
959  status = nc_inq_varid( outfile.gid[0], varname.c_str(), &varid);
960  status = nc_put_var_double( outfile.gid[0], varid, finder_time);
961  check_err(status,__LINE__,__FILE__);
962 
963  varname.assign( "finder_delta_time");
964  status = nc_inq_varid( outfile.gid[0], varname.c_str(), &varid);
965  status = nc_put_var_int( outfile.gid[0], varid, finder_delta_time);
966  check_err(status,__LINE__,__FILE__);
967  }
968 
970 
971  size_t startNav[2]={0, 0};
972  size_t countNav[2]={1, 1};
973 
974  int offadcs;
975  double min;
976  size_t ngood;
977 
978  // ATTITUDE
979  offadcs = 0;
980  min = attitude[0]->sec;
981  for (size_t i=1; i<n[ATTITUDE]; i++) {
982  // cout << i << " " << attitude[i]->sec << endl;
983  if (attitude[i]->sec < min) {
984  offadcs = i;
985  min = attitude[i]->sec;
986  }
987  }
988 
989  ngood = nSC;
990  for (size_t i=offadcs+1; i<n[ATTITUDE]; i++) {
991  if ((attitude[i]->sec-attitude[i-1]->sec) < 0) {
992  ngood = i - offadcs;
993  break;
994  }
995  }
996  if (ngood > nSC) ngood = nSC;
997  if (n[ATTITUDE] == 0) {
998  ngood = 0; // Set to 0 if no attitude records
999  cout << "No attitude records written" << endl;
1000  }
1001 
1002  varname.assign( "att_time");
1003  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1004  for (size_t i=0; i<ngood; i++) {
1005  startNav[0] = i;
1006  status = nc_put_vara_double( outfile.gid[2], varid, startNav, countNav,
1007  &attitude[i+offadcs]->sec);
1008  check_err(status,__LINE__,__FILE__);
1009  }
1010 
1011  varname.assign( "att_quat");
1012  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1013  for (size_t i=0; i<ngood; i++) {
1014  startNav[0] = i;
1015  countNav[1] = 4;
1016  status = nc_put_vara_float( outfile.gid[2], varid, startNav, countNav,
1017  &attitude[i+offadcs]->quat[0]);
1018  check_err(status,__LINE__,__FILE__);
1019  }
1020 
1021  // PROPAGATOR
1022  offadcs = 0;
1023  min = propagator[0]->sec;
1024  for (size_t i=1; i<n[PROPAGATOR]; i++) {
1025  // cout << i << " " << propagator[i]->sec << endl;
1026  if (propagator[i]->sec < min) {
1027  offadcs = i;
1028  min = propagator[i]->sec;
1029  }
1030  }
1031 
1032  ngood = nSC;
1033  for (size_t i=offadcs+1; i<n[PROPAGATOR]; i++) {
1034  if ((propagator[i]->sec-propagator[i-1]->sec) < 0) {
1035  ngood = i - offadcs;
1036  break;
1037  }
1038  }
1039  if (ngood > nSC) ngood = nSC;
1040  if (n[PROPAGATOR] == 0) {
1041  ngood = 0; // Set to 0 if no propagator records
1042  cout << "No progagator records written" << endl;
1043  }
1044 
1045  varname.assign( "orb_time");
1046  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1047  for (size_t i=0; i<ngood; i++) {
1048  startNav[0] = i;
1049  status = nc_put_vara_double( outfile.gid[2], varid, startNav, countNav,
1050  &propagator[i+offadcs]->sec);
1051  check_err(status,__LINE__,__FILE__);
1052  }
1053 
1054  varname.assign( "orb_pos");
1055  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1056  for (size_t i=0; i<ngood; i++) {
1057  startNav[0] = i;
1058  countNav[1] = 3;
1059  status = nc_put_vara_float( outfile.gid[2], varid, startNav, countNav,
1060  &propagator[i+offadcs]->pos[0]);
1061  check_err(status,__LINE__,__FILE__);
1062  }
1063 
1064  varname.assign( "orb_vel");
1065  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1066  for (size_t i=0; i<ngood; i++) {
1067  startNav[0] = i;
1068  countNav[1] = 3;
1069  status = nc_put_vara_float( outfile.gid[2], varid, startNav, countNav,
1070  &propagator[i+offadcs]->vel[0]);
1071  check_err(status,__LINE__,__FILE__);
1072  }
1073 
1074 
1075  // SENSOR
1076  offadcs = 0;
1077  min = sensor[0]->sec;
1078  for (size_t i=1; i<n[SENSOR]; i++) {
1079  // cout << i << " " << sensor[i]->sec << endl;
1080  if (sensor[i]->sec < min) {
1081  offadcs = i;
1082  min = sensor[i]->sec;
1083  }
1084  }
1085 
1086  ngood = nSC;
1087  for (size_t i=offadcs+1; i<n[SENSOR]; i++) {
1088  if ((sensor[i]->sec-sensor[i-1]->sec) < 0) {
1089  ngood = i - offadcs;
1090  break;
1091  }
1092  }
1093  if (ngood > nSC) ngood = nSC; // LH, 7/12/2021
1094  if (ngood > n[SENSOR]) ngood = n[SENSOR]; // LH, 01/15/2021
1095  if (ngood == 0) {
1096  cout << "No sensor records written" << endl;
1097  }
1098 
1099  varname.assign( "sensor_time");
1100  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1101  for (size_t i=0; i<ngood; i++) {
1102  startNav[0] = i;
1103  status = nc_put_vara_double( outfile.gid[2], varid, startNav, countNav,
1104  &sensor[i+offadcs]->sec);
1105  check_err(status,__LINE__,__FILE__);
1106  }
1107 
1108  varname.assign( "sensor_bus_telemetry");
1109  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1110  for (size_t i=0; i<ngood; i++) {
1111  startNav[0] = i;
1112  countNav[1] = 27;
1113  status = nc_put_vara_ubyte( outfile.gid[2], varid, startNav, countNav,
1114  &sensor[i+offadcs]->bus_telemetry[0]);
1115  check_err(status,__LINE__,__FILE__);
1116  }
1117 
1118 
1119  // PSENSOR
1120  offadcs = 0;
1121  min = psensor[0]->sec;
1122  for (size_t i=1; i<n[PSENSOR]; i++) {
1123  // cout << i << " " << psensor[i]->sec << endl;
1124  if (psensor[i]->sec < min) {
1125  offadcs = i;
1126  min = psensor[i]->sec;
1127  }
1128  }
1129 
1130  ngood = nSC;
1131  for (size_t i=offadcs+1; i<n[PSENSOR]; i++) {
1132  if ((psensor[i]->sec-psensor[i-1]->sec) < 0) {
1133  ngood = i - offadcs;
1134  break;
1135  }
1136  }
1137  if (ngood > nSC) ngood = nSC;
1138  if (n[PSENSOR] == 0) {
1139  ngood = 0; // Set to 0 if no psensor records
1140  cout << "No psensor records written" << endl;
1141  }
1142 
1143  varname.assign( "processed_sensor_time");
1144  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1145  for (size_t i=0; i<ngood; i++) {
1146  startNav[0] = i;
1147  status = nc_put_vara_double( outfile.gid[2], varid, startNav, countNav,
1148  &psensor[i+offadcs]->sec);
1149  check_err(status,__LINE__,__FILE__);
1150  }
1151 
1152  varname.assign( "gyro_rates");
1153  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1154  for (size_t i=0; i<ngood; i++) {
1155  startNav[0] = i;
1156  countNav[1] = 3;
1157  status = nc_put_vara_float( outfile.gid[2], varid, startNav, countNav,
1158  &psensor[i+offadcs]->gyro[0]);
1159  check_err(status,__LINE__,__FILE__);
1160  }
1161 
1162  varname.assign( "mag1");
1163  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1164  for (size_t i=0; i<ngood; i++) {
1165  startNav[0] = i;
1166  countNav[1] = 3;
1167  status = nc_put_vara_float( outfile.gid[2], varid, startNav, countNav,
1168  &psensor[i+offadcs]->mag1[0]);
1169  check_err(status,__LINE__,__FILE__);
1170  }
1171 
1172  varname.assign( "mag2");
1173  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1174  for (size_t i=0; i<ngood; i++) {
1175  startNav[0] = i;
1176  countNav[1] = 3;
1177  status = nc_put_vara_float( outfile.gid[2], varid, startNav, countNav,
1178  &psensor[i+offadcs]->mag2[0]);
1179  check_err(status,__LINE__,__FILE__);
1180  }
1181 
1182  varname.assign( "rwheels");
1183  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1184  for (size_t i=0; i<ngood; i++) {
1185  startNav[0] = i;
1186  countNav[1] = 3;
1187  status = nc_put_vara_float( outfile.gid[2], varid, startNav, countNav,
1188  &psensor[i+offadcs]->rwheels[0]);
1189  check_err(status,__LINE__,__FILE__);
1190  }
1191 
1192  varname.assign( "sun_vector");
1193  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1194  for (size_t i=0; i<ngood; i++) {
1195  startNav[0] = i;
1196  countNav[1] = 3;
1197  status = nc_put_vara_float( outfile.gid[2], varid, startNav, countNav,
1198  &psensor[i+offadcs]->sunb[0]);
1199  check_err(status,__LINE__,__FILE__);
1200  }
1201 
1202  outfile.close();
1203 
1204  return 0;
1205 }
1206 
1207 
1208 /*----------------------------------------------------------------- */
1209 /* Create an Generic NETCDF4 level1 file */
1210 /* ---------------------------------------------------------------- */
1211 int l1aFile::createl1( char* l1_filename, uint32_t nSC,
1212  uint32_t imgWidth, uint32_t imgHeight,
1213  uint32_t fndWidth, uint32_t fndHeight) {
1214 
1215  int status;
1216 
1217  status = nc_create( l1_filename, NC_NETCDF4, &ncid);
1218  check_err(status,__LINE__,__FILE__);
1219 
1220  ifstream hawkeye_l1a_data_structure;
1221  string line;
1222  string dataStructureFile;
1223 
1224  dataStructureFile.assign("$OCDATAROOT/hawkeye/Hawkeye_Level-1A_Data_Structure.cdl");
1225  expandEnvVar( &dataStructureFile);
1226 
1227  hawkeye_l1a_data_structure.open( dataStructureFile.c_str(), ifstream::in);
1228  if ( hawkeye_l1a_data_structure.fail() == true) {
1229  cout << "\"" << dataStructureFile.c_str() << "\" not found" << endl;
1230  exit(1);
1231  }
1232 
1233  // Find "dimensions" section of CDL file
1234  while(1) {
1235  getline( hawkeye_l1a_data_structure, line);
1236  size_t pos = line.find("dimensions:");
1237  if ( pos == 0) break;
1238  }
1239 
1240  // Define dimensions from "dimensions" section of CDL file
1241  ndims = 0;
1242  //int32_t numScans=0;
1243  while(1) {
1244  getline( hawkeye_l1a_data_structure, line);
1245  size_t pos = line.find(" = ");
1246  if ( pos == string::npos) break;
1247 
1248  uint32_t dimSize;
1249  istringstream iss(line.substr(pos+2, string::npos));
1250  iss >> dimSize;
1251 
1252  iss.clear();
1253  iss.str( line);
1254  iss >> skipws >> line;
1255 
1256  // cout << "Dimension Name: " << line.c_str() << " Dimension Size: "
1257  // << dimSize << endl;
1258 
1259  //if (line.compare("number_of_scans") == 0 && numScans > 0) {
1260  // dimSize = numScans;
1261  //}
1262 
1263  if (line.compare("number_of_SC_records") == 0) {
1264  dimSize = nSC;
1265  }
1266 
1267  if (line.compare("number_of_scans") == 0) {
1268  dimSize = imgHeight;
1269  }
1270 
1271  if (line.compare("number_of_pixels") == 0) {
1272  dimSize = imgWidth;
1273  }
1274 
1275  if (line.compare("finder_lines") == 0) {
1276  dimSize = fndHeight;
1277  }
1278 
1279  if (line.compare("finder_pixels") == 0) {
1280  dimSize = fndWidth;
1281  }
1282 
1283  status = nc_def_dim( ncid, line.c_str(), dimSize, &dimid[ndims++]);
1284  check_err(status,__LINE__,__FILE__);
1285 
1286  } // while loop
1287 
1288  // Read global attributes (string attributes only)
1289  while(1) {
1290  getline( hawkeye_l1a_data_structure, line);
1291  size_t pos = line.find("// global attributes");
1292  if ( pos == 0) break;
1293  }
1294 
1295  while(1) {
1296  getline( hawkeye_l1a_data_structure, line);
1297  size_t pos = line.find(" = ");
1298  if ( pos == string::npos) break;
1299 
1300  string attValue;
1301 
1302  // Remove leading and trailing quotes
1303  attValue.assign(line.substr(pos+4));
1304  size_t posQuote = attValue.find("\"");
1305  attValue.assign(attValue.substr(0, posQuote));
1306 
1307  istringstream iss(line.substr(pos+2));
1308  iss.clear();
1309  iss.str( line);
1310  iss >> skipws >> line;
1311 
1312  // Skip commented out attributes
1313  if (line.compare("//") == 0) continue;
1314 
1315  string attName;
1316  attName.assign(line.substr(1).c_str());
1317 
1318  // Skip non-string attributes
1319  if (attName.compare("orbit_number") == 0) continue;
1320  if (attName.compare("history") == 0) continue;
1321  if (attName.compare("format_version") == 0) continue;
1322  if (attName.compare("instrument_number") == 0) continue;
1323  if (attName.compare("pixel_offset") == 0) continue;
1324  if (attName.compare("number_of_filled_scans") == 0) continue;
1325 
1326  // cout << attName.c_str() << " " << attValue.c_str() << endl;
1327 
1328  status = nc_put_att_text(ncid, NC_GLOBAL, attName.c_str(),
1329  strlen(attValue.c_str()), attValue.c_str());
1330  check_err(status,__LINE__,__FILE__);
1331 
1332  } // while(1)
1333 
1334 
1335  ngrps = 0;
1336  // Loop through groups
1337  while(1) {
1338  getline( hawkeye_l1a_data_structure, line);
1339 
1340  // Check if end of CDL file
1341  // If so then close CDL file and return
1342  if (line.substr(0,1).compare("}") == 0) {
1343  hawkeye_l1a_data_structure.close();
1344  return 0;
1345  }
1346 
1347  // Check for beginning of new group
1348  size_t pos = line.find("group:");
1349 
1350  // If found then create new group and variables
1351  if ( pos == 0) {
1352 
1353  // Parse group name
1354  istringstream iss(line.substr(6, string::npos));
1355  iss >> skipws >> line;
1356 
1357  // Create NCDF4 group
1358  status = nc_def_grp( ncid, line.c_str(), &gid[ngrps]);
1359  check_err(status,__LINE__,__FILE__);
1360 
1361  ngrps++;
1362 
1363  int numDims=0;
1364  int varDims[NC_MAX_DIMS];
1365  size_t dimSize[NC_MAX_DIMS];
1366  char dimName[NC_MAX_NAME+1];
1367  string sname;
1368  string lname;
1369  string standard_name;
1370  string units;
1371  string flag_values;
1372  string flag_meanings;
1373  double valid_min=0.0;
1374  double valid_max=0.0;
1375  double fill_value=0.0;
1376  float scale_factor=1.0;
1377  float add_offset=0.0;
1378 
1379  int ntype=0;
1380 
1381  // Loop through datasets in group
1382  getline( hawkeye_l1a_data_structure, line); // skip "variables:"
1383  while(1) {
1384  getline( hawkeye_l1a_data_structure, line);
1385 
1386  if (line.length() == 0) continue;
1387  if (line.substr(0,1).compare("\r") == 0) continue;
1388  if (line.substr(0,1).compare("\n") == 0) continue;
1389 
1390  size_t pos = line.find(":");
1391 
1392  // No ":" found, new dataset or empty line or end-of-group
1393  if ( pos == string::npos) {
1394 
1395  if ( numDims > 0) {
1396  // Create previous dataset
1397  createNCDF( gid[ngrps-1],
1398  sname.c_str(), lname.c_str(),
1399  standard_name.c_str(), units.c_str(),
1400  (void *) &fill_value,
1401  flag_values.c_str(), flag_meanings.c_str(),
1402  valid_min, valid_max, scale_factor, add_offset, ntype, numDims, varDims);
1403 
1404  flag_values.assign("");
1405  flag_meanings.assign("");
1406  units.assign("");
1407  }
1408 
1409  valid_min=0.0;
1410  valid_max=0.0;
1411  fill_value=0.0;
1412 
1413  if (line.substr(0,10).compare("} // group") == 0) break;
1414 
1415  // Parse variable type
1416  string varType;
1417  istringstream iss(line);
1418  iss >> skipws >> varType;
1419 
1420  // Get corresponding NC variable type
1421  if ( varType.compare("char") == 0) ntype = NC_CHAR;
1422  else if ( varType.compare("byte") == 0) ntype = NC_BYTE;
1423  else if ( varType.compare("short") == 0) ntype = NC_SHORT;
1424  else if ( varType.compare("int") == 0) ntype = NC_INT;
1425  else if ( varType.compare("long") == 0) ntype = NC_INT;
1426  else if ( varType.compare("float") == 0) ntype = NC_FLOAT;
1427  else if ( varType.compare("real") == 0) ntype = NC_FLOAT;
1428  else if ( varType.compare("double") == 0) ntype = NC_DOUBLE;
1429  else if ( varType.compare("ubyte") == 0) ntype = NC_UBYTE;
1430  else if ( varType.compare("ushort") == 0) ntype = NC_USHORT;
1431  else if ( varType.compare("uint") == 0) ntype = NC_UINT;
1432  else if ( varType.compare("int64") == 0) ntype = NC_INT64;
1433  else if ( varType.compare("uint64") == 0) ntype = NC_UINT64;
1434 
1435  // Parse short name (sname)
1436  pos = line.find("(");
1437  size_t posSname = line.substr(0, pos).rfind(" ");
1438  sname.assign(line.substr(posSname+1, pos-posSname-1));
1439  //cout << "sname: " << sname.c_str() << endl;
1440 
1441  // Parse variable dimension info
1442  this->parseDims( line.substr(pos+1, string::npos),
1443  &numDims, varDims);
1444  for (int i=0; i<numDims; i++) {
1445  nc_inq_dim( ncid, varDims[i], dimName, &dimSize[i]);
1446  //cout << line.c_str() << " " << i << " " << dimName
1447  // << " " << dimSize[i] << endl;
1448  }
1449 
1450  } else {
1451  // Parse variable attributes
1452  size_t posEql = line.find("=");
1453  size_t pos1qte = line.find("\"");
1454  size_t pos2qte = line.substr(pos1qte+1, string::npos).find("\"");
1455  // cout << line.substr(pos+1, posEql-pos-2).c_str() << endl;
1456 
1457  string attrName = line.substr(pos+1, posEql-pos-2);
1458 
1459  // Get long_name
1460  if ( attrName.compare("long_name") == 0) {
1461  lname.assign(line.substr(pos1qte+1, pos2qte));
1462  // cout << "lname: " << lname.c_str() << endl;
1463  }
1464 
1465  // Get units
1466  else if ( attrName.compare("units") == 0) {
1467  units.assign(line.substr(pos1qte+1, pos2qte));
1468  // cout << "units: " << units.c_str() << endl;
1469  }
1470 
1471  // Get _FillValue
1472  else if ( attrName.compare("_FillValue") == 0) {
1473  iss.clear();
1474  iss.str( line.substr(posEql+1, string::npos));
1475  iss >> fill_value;
1476  // cout << "_FillValue: " << fill_value << endl;
1477  }
1478 
1479  // Get flag_values
1480  else if ( attrName.compare("flag_values") == 0) {
1481  flag_values.assign(line.substr(pos1qte+1, pos2qte));
1482  }
1483 
1484  // Get flag_meanings
1485  else if ( attrName.compare("flag_meanings") == 0) {
1486  flag_meanings.assign(line.substr(pos1qte+1, pos2qte));
1487  }
1488 
1489  // Get valid_min
1490  else if ( attrName.compare("valid_min") == 0) {
1491  iss.clear();
1492  iss.str( line.substr(posEql+1, string::npos));
1493  iss >> valid_min;
1494  // cout << "valid_min: " << valid_min << endl;
1495  }
1496 
1497  // Get valid_max
1498  else if ( attrName.compare("valid_max") == 0) {
1499  iss.clear();
1500  iss.str( line.substr(posEql+1, string::npos));
1501  iss >> valid_max;
1502  // cout << "valid_max: " << valid_max << endl;
1503  }
1504 
1505  } // if ( pos == string::npos)
1506  } // datasets in group loop
1507  } // New Group loop
1508  } // Main Group loop
1509 
1510  return 0;
1511 }
1512 
1513 
1514 int l1aFile::parseDims( string dimString, int *numDims, int *varDims) {
1515 
1516  size_t dimSize, curPos=0;
1517  char dimName[NC_MAX_NAME+1];
1518 
1519  *numDims = 0;
1520 
1521  while(1) {
1522  size_t pos = dimString.find(",", curPos);
1523  if ( pos == string::npos)
1524  pos = dimString.find(")");
1525 
1526  string varDimName;
1527  istringstream iss(dimString.substr(curPos, pos-curPos));
1528  iss >> skipws >> varDimName;
1529 
1530  for (int i=0; i<ndims; i++) {
1531  int status = nc_inq_dim( ncid, dimid[i], dimName, &dimSize);
1532  check_err(status,__LINE__,__FILE__);
1533  if ( varDimName.compare(dimName) == 0) {
1534  varDims[(*numDims)++] = dimid[i];
1535  break;
1536  }
1537  }
1538  if ( dimString.substr(pos, 1).compare(")") == 0) break;
1539 
1540  curPos = pos + 1;
1541  }
1542 
1543  return 0;
1544 }
1545 
1546 
1548 
1549  int status = nc_close(ncid);
1550 
1551  if (status != NC_NOERR)
1552  {
1553  printf("-E - nc_close failed for ncid: %i\n",ncid);
1554  }
1555  return 0;
1556 }
1557 
1558 
1559 int unpack_seahawk_adcs( uint8_t *apkt, double startHWKTime, double stopHWKTime,
1560  sensor_t *sensor, psensor_t *psensor,
1561  attitude_t *attitude, propagator_t *propagator) {
1562 
1563  int16_t i16;
1564  int32_t i32;
1565  int32_t iyr, idy;
1566  int32_t startdy, stopdy;
1567  double sec;
1568 
1569  short psub = apkt[8];
1570 
1571  // Get time
1572 
1573  // JD 2015/01/01 = 2457023.5
1574  // JD 1980/01/06 = 2444244.5
1575  // delta sec = (2457023.5-2444244.5) * 24 * 3600 = 1104105600
1576  // Add 16 leapsecs between 1980/01/06 and 2015/01/01
1577 
1578  memcpy(&i32, &apkt[9], 4);
1579  double tepoch = (double) __builtin_bswap32(i32) - (1104105600+16);
1580 
1581  // cout << tepoch - startHWKTime << endl;
1582  if ( (startHWKTime-tepoch) > 2 || (tepoch - stopHWKTime) > 1) {
1583  return -1;
1584  }
1585 
1586  tepoch2yds( startHWKTime, &iyr, &idy, &sec);
1587  startdy = iyr*1000 + idy;
1588  tepoch2yds( stopHWKTime, &iyr, &idy, &sec);
1589  stopdy = iyr*1000 + idy;
1590 
1591  tepoch2yds( tepoch, &iyr, &idy, &sec);
1592  memcpy(&i32, &apkt[13], 4);
1593  sec += ((double) __builtin_bswap32(i32)) / 4294967296.0;
1594  memcpy(&i16, &apkt[17], 2);
1595  sec -= ((double) SWAP_2(i16)) / 1000;
1596  // if the image spans over 00:00, the sec of day for earlier part of image is from previous day,
1597  // ending with a value close to 86400
1598  if ((stopdy>startdy) && (sec<80000)) sec += 86400.0;
1599 
1600  switch (psub) {
1601  case 1:
1602  sensor->iyr = iyr;
1603  sensor->iday = idy;
1604  sensor->sec = sec;
1605  memcpy(sensor->bus_telemetry, &apkt[19], sizeof(sensor->bus_telemetry));
1606  break;
1607 
1608  case 2:
1609  psensor->iyr = iyr;
1610  psensor->iday = idy;
1611  psensor->sec = sec;
1612  for (size_t i=0; i<3; i++) {
1613  memcpy(&i32, &apkt[19+4*i], 4);
1614  i32 = __builtin_bswap32(i32);
1615  memcpy(&psensor->gyro[i], &i32, 4);
1616 
1617  memcpy(&i32, &apkt[31+4*i], 4);
1618  i32 = __builtin_bswap32(i32);
1619  memcpy(&psensor->mag1[i], &i32, 4);
1620 
1621  memcpy(&i32, &apkt[43+4*i], 4);
1622  i32 = __builtin_bswap32(i32);
1623  memcpy(&psensor->mag2[i], &i32, 4);
1624 
1625  memcpy(&i32, &apkt[55+4*i], 4);
1626  i32 = __builtin_bswap32(i32);
1627  memcpy(&psensor->rwheels[i], &i32, 4);
1628 
1629  memcpy(&i32, &apkt[67+4*i], 4);
1630  i32 = __builtin_bswap32(i32);
1631  memcpy(&psensor->sunb[i], &i32, 4);
1632  }
1633  break;
1634 
1635  case 3:
1636  attitude->iyr = iyr;
1637  attitude->iday = idy;
1638  attitude->sec = sec;
1639  for (size_t i=0; i<4; i++) {
1640  memcpy(&i32, &apkt[19+4*i], 4);
1641  i32 = __builtin_bswap32(i32);
1642  memcpy(&attitude->quat[i], &i32, 4);
1643  }
1644  break;
1645 
1646  case 4:
1647  propagator->iyr = iyr;
1648  propagator->iday = idy;
1649  propagator->sec = sec;
1650  for (size_t i=0; i<3; i++) {
1651  memcpy(&i32, &apkt[19+4*i], 4);
1652  i32 = __builtin_bswap32(i32);
1653  memcpy(&propagator->pos[i], &i32, 4);
1654 
1655  memcpy(&i32, &apkt[31+4*i], 4);
1656  i32 = __builtin_bswap32(i32);
1657  memcpy(&propagator->vel[i], &i32, 4);
1658  }
1659  break;
1660  }
1661 
1662  return 0;
1663 }
1664 
1665 
@ TC_FPGA_VERSION
Definition: Hawkeye.h:91
uint16_t spectralBinning
Definition: HawkeyeDecode.h:53
@ TC_CCD4_TEMP
Definition: Hawkeye.h:92
int32 value
Definition: Granule.c:1235
float gyro[3]
HawkeyeImageInfo imageInfo
Definition: HawkeyeDecode.h:82
a context in which it is NOT documented to do so subscript which cannot be easily calculated when extracting TONS attitude data from the Terra L0 files Corrected several defects in extraction of entrained ephemeris and attitude
Definition: HISTORY.txt:61
int main(int argc, char *argv[])
HAWKEYE_STREAM_ERROR HawkeyeScanStream(uint8_t *stream, uint32_t streamLength, HawkeyeStreamInfo *streamInfo)
@ TC_FPGA_VNVP
Definition: Hawkeye.h:92
float vel[3]
float * hgt
int j
Definition: decode_rs.h:73
uint16_t channelInterp
Definition: Hawkeye.h:157
int status
Definition: l1_czcs_hdf.c:32
double yds2unix(int16_t year, int16_t day, double secs)
Definition: yds2unix.c:7
void check_err(const int stat, const int line, const char *file)
Definition: nc4utils.c:35
HAWKEYE_STREAM_ERROR HawkeyeDecodeSpectralImage(uint16_t bandNo, uint16_t *pixels, uint32_t pixelLength, uint16_t *averageDarkPixels, uint16_t averageDarkPixelLength)
uint16_t channelBitfield
Definition: HawkeyeDecode.h:55
@ TC_AD7490_CH04
Definition: Hawkeye.h:93
uint16_t errorCode
Definition: HawkeyeDecode.h:47
These are used to scale the SD before writing it to the HDF4 file The default is and which means the product is not scaled at all Since the product is usually stored as a float inside of this is a way to write the float out as a integer l2prod min
uint16_t ccd1Exposure
Definition: HawkeyeDecode.h:56
@ TC_CCD_VDD_OC
Definition: Hawkeye.h:92
int createl1(char *l1_filename, uint32_t nSC, uint32_t imgWidth, uint32_t imgHeight, uint32_t fndWidth, uint32_t fndHeight)
int expandEnvVar(std::string *sValue)
Definition: ancgen.cpp:222
uint16_t finderscopeExposure
Definition: HawkeyeDecode.h:64
uint16_t darkSubtracted
Definition: HawkeyeDecode.h:67
float mag1[3]
@ TC_FPGA_TEMP
Definition: Hawkeye.h:92
#define NULL
Definition: decode_rs.h:63
real, dimension(260) sb
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed as required for compatibility with version of the SDP toolkit Corrected test output file names to end in out
Definition: HISTORY.txt:422
@ TC_AD7490_CH05
Definition: Hawkeye.h:93
uint16_t shutterSolenoid
Definition: HawkeyeDecode.h:68
int unpack_seahawk_adcs(uint8_t *apkt, double startHWKTime, double stopHWKTime, sensor_t *sensor, psensor_t *psensor, attitude_t *attitude, propagator_t *propagator)
uint16_t ccd4Exposure
Definition: HawkeyeDecode.h:59
uint16_t darkHeight
Definition: HawkeyeDecode.h:61
float32 * pos
Definition: l1_czcs_hdf.c:35
HAWKEYE_STREAM_ERROR HawkeyeDecodeFinderscopeImage(uint16_t imageNo, uint16_t *pixels, uint32_t pixelLength)
@ TC_AD7490_CH16
Definition: Hawkeye.h:94
#define FINDERSCOPE_MAX_IMAGES
Definition: Hawkeye.h:28
uint16_t ccd3Exposure
Definition: HawkeyeDecode.h:58
@ TC_FPGA_VAUX
Definition: Hawkeye.h:92
TelemetryPair channel[TC_NO_CHANNELS]
Definition: Hawkeye.h:161
uint16_t channelValue
Definition: Hawkeye.h:156
int tepoch2yds(double tepoch, int32_t *iyr, int32_t *idy, double *sec)
float sunb[3]
@ PSENSOR
@ TC_AD7490_CH09
Definition: Hawkeye.h:94
uint32_t exposureID
Definition: HawkeyeDecode.h:48
double sec
uint16_t oversampling
Definition: HawkeyeDecode.h:63
@ HSE_NO_HEADER_FOUND
Definition: HawkeyeDecode.h:22
@ TC_AD7490_CH14
Definition: Hawkeye.h:94
@ TC_AD7490_CH15
Definition: Hawkeye.h:94
uint32_t hawkeyeDeltaEpoch
Definition: HawkeyeDecode.h:52
@ TC_SOFTWARE_VERSION
Definition: Hawkeye.h:91
@ TC_AD7490_CH08
Definition: Hawkeye.h:93
@ TC_CCD2_TEMP
Definition: Hawkeye.h:91
@ TC_CCD3_TEMP
Definition: Hawkeye.h:92
#define SENSOR
int parseDims(string dimString, int *numDims, int *varDims)
@ TC_AD7490_CH03
Definition: Hawkeye.h:93
HawkeyeBandInfo finderscopeInfo[MAX_FINDERSCOPE_IMAGES]
Definition: HawkeyeDecode.h:86
GetTelemetryResponse telemetry
Definition: HawkeyeDecode.h:43
@ TC_AD7490_CH07
Definition: Hawkeye.h:93
uint16_t finderscopeBinning
Definition: HawkeyeDecode.h:54
uint32_t timeStamp
Definition: HawkeyeDecode.h:33
@ TC_AD7490_CH10
Definition: Hawkeye.h:94
#define MAXNPACKETS
int parseDims(int ncid, int ndims, string dimString, int *numDims, int *dimid, int *varDims)
integer, parameter double
@ PROPAGATOR
#define SWAP_2(x)
SENSOR
Definition: DDProcess.h:81
@ TC_FPGA_VINT
Definition: Hawkeye.h:92
float mag2[3]
DATA_COMPRESSION compression
Definition: HawkeyeDecode.h:66
@ TC_AD7490_CH01
Definition: Hawkeye.h:93
uint16_t readoutOrder
Definition: HawkeyeDecode.h:69
@ ATTITUDE
@ TC_AD7490_CH11
Definition: Hawkeye.h:94
int createNCDF(int ncid, const char *sname, const char *lname, const char *standard_name, const char *units, void *fill_value, const char *flag_values, const char *flag_meanings, double low, double high, float scale_factor, float add_offset, int nt, int rank, int *dimids)
@ TC_CCD1_TEMP
Definition: Hawkeye.h:91
@ TC_AD7490_CH02
Definition: Hawkeye.h:93
u5 which has been done in the LOCALGRANULEID metadata should have an extension NRT It is requested to identify the NRT production Changes from v6 which may affect scientific the sector rotation may actually occur during one of the scans earlier than the one where it is first reported As a the b1 values are about the LOCALGRANULEID metadata should have an extension NRT It is requested to identify the NRT to fill pixels affected by dead subframes with a special value Output the metadata of noisy and dead subframe Dead Subframe EV and Detector Quality Flag2 Removed the function call of Fill_Dead_Detector_SI to stop interpolating SI values for dead but also for all downstream products for science test only Changes from v5 which will affect scientific to conform to MODIS requirements Removed the Mixed option from the ScanType in the code because the L1A Scan Type is never Mixed Changed for ANSI C compliance and comments to better document the fact that when the HDF_EOS metadata is stricly the and products are off by and in the track respectively Corrected some misspelling of RCS swir_oob_sending_detector to the Reflective LUTs to enable the SWIR OOB correction detector so that if any of the sending detectors becomes noisy or non near by good detectors from the same sending band can be specified as the substitute in the new look up table Code change for adding an additional dimension of mirror side to the Band_21_b1 LUT to separate the coefficient of the two mirror sides for just like other thermal emissive so that the L1B code can calibrate Band scan to scan with mirror side dependency which leads better calibration result Changes which do not affect scientific when the EV data are not provided in this Crosstalk Correction will not be performed to the Band calibration data Changes which do not affect scientific and BB_500m in L1A Logic was added to turn off the or to spatial aggregation processes and the EV_250m_Aggr1km_RefSB and EV_500m_Aggr1km_RefSB fields were set to fill values when SDSs EV_250m and EV_500m are absent in L1A file Logic was added to skip the processing and turn off the output of the L1B QKM and HKM EV data when EV_250m and EV_500m are absent from L1A In this the new process avoids accessing and reading the and L1A EV skips and writing to the L1B and EV omits reading and subsampling SDSs from geolocation file and writing them to the L1B and omits writing metadata to L1B and EV and skips closing the L1A and L1B EV and SDSs Logic was added to turn off the L1B OBC output when the high resolution OBC SDSs are absent from L1A This is accomplished by skipping the openning the writing of metadata and the closing of the L1B OBC hdf which is Bit in the scan by scan bit QA has been changed Until now
Definition: HISTORY.txt:361
uint32_t hostDeltaEpoch
Definition: HawkeyeDecode.h:51
char * unix2isodate(double dtime, char zone)
Definition: unix2isodate.c:10
float rwheels[3]
@ HSE_NO_ERROR
Definition: HawkeyeDecode.h:22
uint16_t ccd2Exposure
Definition: HawkeyeDecode.h:57
int16_t iday
@ TC_AD7490_CH12
Definition: Hawkeye.h:94
#define VERSION
uint16_t noFinderscopeImages
Definition: HawkeyeDecode.h:65
@ TC_AD7490_CH13
Definition: Hawkeye.h:94
int32_t idy
Definition: atrem_corl1.h:161
HawkeyeBandInfo spectralInfo[8]
Definition: HawkeyeDecode.h:84
@ TC_INDEX
Definition: Hawkeye.h:91
float pos[3]
These two strings are used for the product XML output If product_id is not set then prefix is used If the last char of the name_prefix is _ then it is removed If algorithm_id is not set then name_suffix is used If the first char is _ then it is removed l2prod standard_name[0]
int i
Definition: decode_rs.h:71
HawkeyeTelemetryInfo telemetryInfo[MAX_TELEMETRY_RECORDS]
Definition: HawkeyeDecode.h:88
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
#define MAXIMGHEIGHT
int32_t iyr
Definition: atrem_corl1.h:161
constexpr auto software_version
Definition: Version.hpp:4
Definition: orbit.h:79
int16_t iyr
@ TC_AD7490_CH06
Definition: Hawkeye.h:93
int count
Definition: decode_rs.h:79