OB.DAAC Logo
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.4"
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 
92 using namespace std;
93 
94 // Note: To get an HEB dump just supply to L0 file on the command line.
95 
96 int main (int argc, char* argv[])
97 {
98 
99  cout << "l1agen_hawkeye " << VERSION << " ("
100  << __DATE__ << " " << __TIME__ << ")" << endl;
101 
102  if ( argc == 1) {
103  cout << endl <<
104  "l1agen_hawkeye " <<
105  "input_l0_filename input_l0_textfilename output_l1a_filename" << endl;
106 
107  return 0;
108  }
109 
110  // Open L0 telemetry file for reading
111  ifstream tlmfile;
112  tlmfile.open( argv[1], ios::binary | ifstream::in);
113 
114 
115  // Open L0 text file
116  istringstream istr;
117  ifstream l0Text;
118  char txtbuf[512];
119  double startHWKTime;
120  double stopHWKTime;
121  bool bImageCrossDay = false;
122  int32_t startyr, startdy, stopyr, stopdy;
123  double startsec, stopsec;
124  uint32_t nSC;
125  if (argc > 2) {
126  l0Text.open( argv[2], ifstream::in);
127  if ( l0Text.fail() != 0) {
128  cout << endl << "L0 Text File: " << argv[2] << " not found." << endl;
129  exit(1);
130  }
131 
132  // Read StartHWKTime/StopHWKTime
133  while( !l0Text.eof()) {
134  size_t found;
135  l0Text.getline( txtbuf, 512);
136  string sValue = txtbuf;
137 
138  found = sValue.find("StartHWKTime");
139  if ( found != string::npos) {
140  found = sValue.find("=");
141  istr.str(sValue.substr(found+1));
142  istr >> startHWKTime;
143  istr.clear();
144  }
145 
146  found = sValue.find( "StopHWKTime");
147  if ( found != string::npos) {
148  found = sValue.find("=");
149  istr.str(sValue.substr(found+1));
150  istr >> stopHWKTime;
151  istr.clear();
152  }
153  }
154 
155  nSC = (uint32_t) (stopHWKTime - startHWKTime) + 2;
156 
157  tepoch2yds(startHWKTime, &startyr, &startdy, &startsec);
158  tepoch2yds(stopHWKTime, &stopyr, &stopdy, &stopsec);
159  if ((stopyr*1000+stopdy)>(startyr*1000+startdy)) bImageCrossDay = true;
160  }
161 
162 
163  // Allocate ADCS data buffer pointer arrays
165  psensor_t *psensor[MAXNPACKETS];
167  propagator_t *propagator[MAXNPACKETS];
168 
169  uint32_t n[4]={0,0,0,0};
170  uint32_t packet_length;
171 
172  // Image data buffer
173  vector<uint8_t> heb_buf;
174 
175  uint8_t **packet = new uint8_t*;
176  uint32_t nImages=0, nFinder=0;
177 
178  // int first = 1;
179  while (1) {
180  int tlmfile_pos = tlmfile.tellg();
181 
182  // int status = get_packet_from_frame( &tlmfile, packet, packet_length,
183  // first);
184 
185  // cout << tlmfile_pos << endl;
186 
187  int status;
188  uint8_t header[6];
189  tlmfile.read( (char *) header, 6);
190 
191  if( tlmfile.eof()) break;
192 
193  int dataLen = header[4]*256 + header[5] - 2;
194  packet_length = 6 + 3 + dataLen;
195  tlmfile.seekg( -6, ios::cur);
196 
197  (*packet) = new uint8_t[packet_length];
198  tlmfile.read( (char *) (*packet), packet_length);
199 
200  // if (status == 1) {
201  //first = 1;
202  // break;
203  //}
204 
205  // Each packet contains a CCSDS 6-byte header followed by a SeaHawk PUS
206  // subheader. The second byte of the subheader indicates the data type:
207 
208  // 253 Hawkeye data
209  // 254 GPS data
210  // 255 ADCS data
211 
212  // The Hawkeye packets are slightly modified versions of the .heb file
213  // blocks. The block start sequence is replaced by the CCSDS header and
214  // the first two bytes of the PUS subheader. The block type is contained
215  // in the third byte of the subheader. Also, the block length field is
216  // now the packet length, which is 7 bytes longer than the CCSDS header
217  // packet length.
218 
219  if ((*packet)[7] == 255) {
220  short psub = (*packet)[8];
221 
222  if (psub == 1) {
223  sensor[n[0]] = new sensor_t;
224  } else if (psub == 2) {
225  psensor[n[1]] = new psensor_t;
226  } else if (psub == 3) {
227  attitude[n[2]] = new attitude_t;
228  } else if (psub == 4) {
229  propagator[n[3]] = new propagator_t;
230  }
231 
232  // Ver 0.995
233  if (n[psub-1] >= MAXNPACKETS-1) {
234  cout << "Insufficient pointer allocation for psub: " << psub << endl;
235  cout << "Increase value of MAXNPACKETS" << endl;
236  continue;
237  }
238 
239  status = unpack_seahawk_adcs( *packet, startHWKTime, stopHWKTime,
240  sensor[n[0]], psensor[n[1]],
241  attitude[n[2]], propagator[n[3]]);
242 
243  if (status == 0) n[psub-1]++;
244 
245  //if (n[psub-1] == MAXNPACKETS) {
246  // cout << "Insufficient pointer allocation for psub: " << psub << endl;
247  // cout << "Increase value of MAXNPACKETS" << endl;
248  // exit(1);
249  //}
250 
251  } else if ((*packet)[7] == 253) {
252  // HEB data
253  uint16_t row;
254 
255  // Compressed Image/Finder Data
256  if ( (*packet)[8] == 2) {
257  uint8_t infoByte = (*packet)[15];
258  uint8_t sb = infoByte & 0x1f;
259 
260  // sd_f: 0 - finder, 1 - spectral (image)
261  uint8_t sd_f = (infoByte & 0x40) >> 6;
262  uint8_t dark = (infoByte & 0x80) >> 7;
263  memcpy(&row, &(*packet)[20], 2);
264  row = SWAP_2(row);
265 
266  if (sd_f == 0 && sb > nFinder) nFinder = sb;
267  if (sd_f == 1 && sb > nImages) nImages = sb;
268 
269  if ( argc == 2) {
270  cout << "SB or Finder #: " << (int) sb <<
271  " SpecData or Finder: " << (int) sd_f <<
272  " Dark: " << (int) dark << " Row #: " << row <<
273  " packet length: " << packet_length <<
274  " tlmfile_pos: " << tlmfile_pos << endl;
275  }
276  }
277 
278  // Image Parameters Data Block
279  if ( (*packet)[8] == 3) {
280  //cout << "Image Parameter" << endl;
281  uint16_t hgt;
282  memcpy(&hgt, &(*packet)[48], 2);
283  // uint8_t nFinder = (*packet)[55];
284  //cout << "SB hgt: " << SWAP_2(hgt) <<
285  // " # find img: " << (int) nFinder << endl;
286  }
287  //if ( (*packet)[8] == 4) cout << "Telemetry" << endl;
288  // if ( (*packet)[8] == 6) cout << "Mission Log" << endl;
289 
290 
291  // Block start sequence
292  uint8_t bss[6] = {0x00,0x00,0xff,0xff,0xff,0xff};
293 
294  // Compute new checksum
295  uint16_t checksum = 4*255;
296  for (size_t i=8; i<packet_length; i++) {
297  checksum += (*packet)[i];
298  }
299  uint16_t swapcheck = SWAP_2(checksum);
300 
301  // Write HEB data
302  heb_buf.insert(heb_buf.end(), bss, bss+6);
303  heb_buf.insert(heb_buf.end(), &(*packet)[8], &(*packet)[packet_length]);
304  heb_buf.push_back(swapcheck & 0x00ff);
305  heb_buf.push_back((swapcheck & 0xff00) >> 8);
306  } else {
307  // cout << (int) (*packet)[7] << " " << (int) (*packet)[8] << endl;
308 
309  }
310  delete[] (*packet);
311  }
312  uint32_t hebBufLength = heb_buf.size();
313 
314  cout << "Number of SENSOR packets: " << n[SENSOR] << endl;
315  cout << "Number of PSENSOR packets: " << n[PSENSOR] << endl;
316  cout << "Number of ATTITUDE packets: " << n[ATTITUDE] << endl;
317  cout << "Number of PROPAGATOR packets: " << n[PROPAGATOR] << endl << endl;
318 
319  cout << "Number of Spectral Images: " << nImages << endl;
320  cout << "Number of Finder Images: " << nFinder << endl << endl;
321 
322  if ( argc == 2) {
323  ofstream hebFile ("heb_buf.bin", ios::out | ios::binary);
324  hebFile.write((char *) heb_buf.data(), hebBufLength);
325  hebFile.close();
326 
327  return 0;
328  }
329 
330  HawkeyeStreamInfo streamInfo;
331  string l1a_name;
332  l1a_name.assign( argv[3]);
333 
334  // Image height is determined by counting the number of "good" rows
335  // Image width is determined in ScanRow() (for each row which are identical)
336  HawkeyeScanStream( (uint8_t*) heb_buf.data(), hebBufLength, &streamInfo);
337 
338  // Bail if empty
339  if ( streamInfo.spectralInfo[0].width == 0) {
340  cout << "Empty output file: " << l1a_name.c_str() << endl;
341  exit(110);
342  }
343 
344  // check image height not to exceed max value in case of corrupted bytes in raw data reading
345  // LH, 1/21/2021
346  // updated band height checking, LH, 8/31/2021
347  uint16_t band_max_height = 0;
348  for (size_t i=0; i<8; i++) {
349  if (streamInfo.spectralInfo[i].height>band_max_height && streamInfo.spectralInfo[i].height<=MAXIMGHEIGHT) {
350  band_max_height = streamInfo.spectralInfo[i].height;
351  }
352  }
353  if (band_max_height==0) {
354  cout << "Image height in all bands exceeds MAXIMGHEIGHT " << endl;
355  //cout << "Empty output file: " << l1a_name.c_str() << endl;
356  //exit(110);
357  band_max_height = MAXIMGHEIGHT;
358  }
359  for (size_t i=0; i<8; i++) {
360  if (streamInfo.spectralInfo[i].height>MAXIMGHEIGHT) {
361  cout << "Image height " <<streamInfo.spectralInfo[i].height<<" in band " <<(i+1)<< " exceeds MAXIMGHEIGHT " << endl;
362  streamInfo.spectralInfo[i].height = band_max_height;
363  }
364  }
365 
366  // Full size: 18 byte offset / 2 byte time code and 16 bytes dark pixels
367  // Half size: 12 byte offset / 2 byte time code and 10 bytes dark pixels
368  uint32_t rowOffset;
369  if ( streamInfo.spectralInfo[0].width == 1816) rowOffset = 18;
370  if ( streamInfo.spectralInfo[0].width == 908) rowOffset = 10;
371 
372  static l1aFile outfile;
373  outfile.createl1( (char *) l1a_name.c_str(), nSC,
374  streamInfo.spectralInfo[0].width+2-rowOffset,
375  streamInfo.spectralInfo[0].height,
376  streamInfo.finderscopeInfo[0].width,
377  streamInfo.finderscopeInfo[0].height);
378 
379  // scan_line_attributes
380  // parameters_telemetry_data
381  // navigation_data
382  // earth_view_data
383 
384  char buf[32];
385  strcpy( buf, unix2isodate(now(), 'G'));
386 
387  int status;
388  int varid;
389  string varname;
390 
391 
393  int dimid;
394  size_t nTlmBlocks, sizeTelBlk, nCCDtemps, nFPGAvolts, nCurrents, nCCDvolts;
395 
396  nc_inq_dimid( outfile.ncid, "number_of_tlm_blocks", &dimid);
397  nc_inq_dimlen( outfile.ncid, dimid, &nTlmBlocks);
398 
399  nc_inq_dimid( outfile.ncid, "telemetry_block", &dimid);
400  nc_inq_dimlen( outfile.ncid, dimid, &sizeTelBlk);
401 
402  nc_inq_dimid( outfile.ncid, "ccd_temps", &dimid);
403  nc_inq_dimlen( outfile.ncid, dimid, &nCCDtemps);
404 
405  nc_inq_dimid( outfile.ncid, "ccd_volts", &dimid);
406  nc_inq_dimlen( outfile.ncid, dimid, &nCCDvolts);
407 
408  nc_inq_dimid( outfile.ncid, "fpga_volts", &dimid);
409  nc_inq_dimlen( outfile.ncid, dimid, &nFPGAvolts);
410 
411  nc_inq_dimid( outfile.ncid, "currents", &dimid);
412  nc_inq_dimlen( outfile.ncid, dimid, &nCurrents);
413 
414 
415  uint16_t *telemetry = new uint16_t[nTlmBlocks*sizeTelBlk];
416  double *tlm_time = new double[nTlmBlocks];
417  uint32_t *tlm_time_stamp = new uint32_t[nTlmBlocks];
418  int16_t *software_version = new int16_t[nTlmBlocks];
419  int16_t *fpga_version = new int16_t[nTlmBlocks];
420  int16_t *telemetry_counter = new int16_t[nTlmBlocks];
421 
422  float *ccd_temperatures = new float[nTlmBlocks*nCCDtemps];
423  for (size_t i=0; i<nTlmBlocks*nCCDtemps; i++) ccd_temperatures[i] = -999.0;
424 
425  float *fpga_temperature = new float[nTlmBlocks];
426  for (size_t i=0; i<nTlmBlocks; i++) fpga_temperature[i] = -999.0;
427 
428  float *fpga_voltages = new float [nTlmBlocks*nFPGAvolts];
429  for (size_t i=0; i<nTlmBlocks*nFPGAvolts; i++) fpga_voltages[i] = -999.0;
430 
431  int16_t *overcurrent = new int16_t[nTlmBlocks];
432 
433  float *current_monitors = new float[nTlmBlocks*nCurrents];
434  for (size_t i=0; i<nTlmBlocks*nCurrents; i++) current_monitors[i] = -999.0;
435 
436  float *ccd_voltages = new float[nTlmBlocks*nCCDvolts];
437  for (size_t i=0; i<nTlmBlocks*nCCDvolts; i++) ccd_voltages[i] = -999.0;
438 
439  float *solenoid_voltage = new float[nTlmBlocks];
440  for (size_t i=0; i<nTlmBlocks; i++) solenoid_voltage[i] = -999.0;
441 
442  int32_t iyr, idy;
443  double sec;
444 
445  for (size_t i=0; i<nTlmBlocks; i++) {
446  // cout << "i: " << i << endl;
447  tlm_time_stamp[i] = streamInfo.telemetryInfo[i].timeStamp;
448 
449  tlm_time[i] = (streamInfo.imageInfo.epochT0 + tlm_time_stamp[i]) * 0.001;
450 
451  // JD 2015/01/01 = 2457023.5
452  // JD 1980/01/06 = 2444244.5
453  // delta sec = (2457023.5-2444244.5) * 24 * 3600 = 1104105600
454  // Add 16 leapsecs between 1980/01/06 and 2015/01/01
455  // Convert to milliseconds: 1104105616000
456  // Subtract 2^40 = 1099511627776
457  // delta = 4593988224
458  // Convert to days: 4593988224 / (24*3600*1000) = 53.17116
459  // 0.17116 * 24 * 3600 = 14788.224;
460 
461  tlm_time[i] -= (53*24*3600 + 14788.224);
462  tepoch2yds( tlm_time[i], &iyr, &idy, &sec);
463 
464  tlm_time[i] = sec;
465  // if image spans two days
466  if (bImageCrossDay && (sec<80000)) tlm_time[i] = sec+86400.0;
467 
468  memcpy( &telemetry[i*sizeTelBlk], &streamInfo.telemetryInfo[i].telemetry,
469  sizeTelBlk*sizeof(short));
470 
471  uint32_t nChannels = streamInfo.telemetryInfo[i].noChannels;
472  for (size_t j=0; j<nChannels; j++) {
473  uint16_t value =
475 
476  uint16_t interp =
478 
479  switch (j) {
480 
481  case TC_SOFTWARE_VERSION:
482  if ( interp == 1)
483  software_version[i] = value;
484  else
485  software_version[i] = -999;
486  break;
487 
488  case TC_FPGA_VERSION:
489  if ( interp == 1)
490  fpga_version[i] = value;
491  else
492  fpga_version[i] = -999;
493  break;
494 
495  case TC_INDEX:
496  if ( interp == 1)
497  telemetry_counter[i] = value;
498  else
499  telemetry_counter[i] = -999;
500  break;
501 
502  case TC_CCD1_TEMP:
503  case TC_CCD2_TEMP:
504  case TC_CCD3_TEMP:
505  case TC_CCD4_TEMP:
506  if ( interp == 1) {
507  // ver 0.998: CCD temperatures are signed values but read as unsigned. LH
508  ccd_temperatures[i*nCCDtemps+(j-TC_CCD1_TEMP)] = (value<32768)? (value / 32.0):(value / 32.0-2048);
509  }
510  if (i*nCCDtemps+(j-TC_CCD1_TEMP)>0) { // ver 0.999: -2 degC readings following an invalid value are flagged as invalid
511  if ((ccd_temperatures[i*nCCDtemps+(j-TC_CCD1_TEMP)-1]==-999.0) && (ccd_temperatures[i*nCCDtemps+(j-TC_CCD1_TEMP)]==-2.0)) {
512  ccd_temperatures[i*nCCDtemps+(j-TC_CCD1_TEMP)] = -999.0;
513  }
514  }
515  else
516  ccd_temperatures[i*nCCDtemps+(j-TC_CCD1_TEMP)] = -999.0;
517  break;
518 
519  case TC_FPGA_TEMP:
520  if ( interp == 1)
521  fpga_temperature[i] = (float) value;
522  else
523  fpga_temperature[i] = -999.0;
524  break;
525 
526  case TC_FPGA_VAUX:
527  case TC_FPGA_VINT:
528  case TC_FPGA_VNVP:
529  if ( interp == 1)
530  fpga_voltages[i*nFPGAvolts+(j-TC_FPGA_VAUX)] = value / 1000.0;
531  else
532  fpga_voltages[i*nFPGAvolts+(j-TC_FPGA_VAUX)] = -999.0;
533  break;
534 
535  case TC_CCD_VDD_OC:
536  if ( interp == 1)
537  overcurrent[i] = value;
538  else
539  overcurrent[i] = -999;
540  break;
541 
542  case TC_AD7490_CH01:
543  case TC_AD7490_CH02:
544  case TC_AD7490_CH03:
545  case TC_AD7490_CH04:
546  if ( interp == 1)
547  current_monitors[i*nCurrents+(j-TC_AD7490_CH01)] = value / 100.0;
548  else
549  current_monitors[i*nCurrents+(j-TC_AD7490_CH01)] = -999.0;
550  break;
551 
552  case TC_AD7490_CH05:
553  case TC_AD7490_CH06:
554  case TC_AD7490_CH07:
555  case TC_AD7490_CH08:
556  case TC_AD7490_CH09:
557  case TC_AD7490_CH10:
558  case TC_AD7490_CH11:
559  case TC_AD7490_CH12:
560  case TC_AD7490_CH13:
561  case TC_AD7490_CH14:
562  case TC_AD7490_CH15:
563  if ( interp == 1)
564  ccd_voltages[i*nCCDvolts+(j-TC_AD7490_CH05)] = value / 1000.0;
565  else
566  ccd_voltages[i*nCCDvolts+(j-TC_AD7490_CH05)] = -999.0;
567  break;
568 
569  case TC_AD7490_CH16:
570  if ( interp == 1)
571  solenoid_voltage[i] = value / 1000.0;
572  else
573  solenoid_voltage[i] = -999.0;
574  }
575  } // channel loop
576 
577  } // tlm block loop
578 
579 
580  varname.assign( "telemetry");
581  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
582  status = nc_put_var_ushort( outfile.gid[1], varid, telemetry);
583  check_err(status,__LINE__,__FILE__);
584 
585  varname.assign( "tlm_time_stamp");
586  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
587  status = nc_put_var_uint( outfile.gid[1], varid, tlm_time_stamp);
588  check_err(status,__LINE__,__FILE__);
589 
590  varname.assign( "tlm_time");
591  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
592  status = nc_put_var_double( outfile.gid[1], varid, tlm_time);
593  check_err(status,__LINE__,__FILE__);
594 
595  varname.assign( "software_version");
596  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
597  status = nc_put_var_short( outfile.gid[1], varid, software_version);
598  check_err(status,__LINE__,__FILE__);
599 
600  varname.assign( "FPGA_version");
601  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
602  status = nc_put_var_short( outfile.gid[1], varid, fpga_version);
603  check_err(status,__LINE__,__FILE__);
604 
605  varname.assign( "telemetry_counter");
606  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
607  status = nc_put_var_short( outfile.gid[1], varid, telemetry_counter);
608  check_err(status,__LINE__,__FILE__);
609 
610  varname.assign( "CCD_temperatures");
611  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
612  status = nc_put_var_float( outfile.gid[1], varid, ccd_temperatures);
613  check_err(status,__LINE__,__FILE__);
614 
615  varname.assign( "FPGA_temperature");
616  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
617  status = nc_put_var_float( outfile.gid[1], varid, fpga_temperature);
618  check_err(status,__LINE__,__FILE__);
619 
620  varname.assign( "FPGA_voltages");
621  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
622  status = nc_put_var_float( outfile.gid[1], varid, fpga_voltages);
623  check_err(status,__LINE__,__FILE__);
624 
625  varname.assign( "overcurrent");
626  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
627  status = nc_put_var_short( outfile.gid[1], varid, overcurrent);
628  check_err(status,__LINE__,__FILE__);
629 
630  varname.assign( "current_monitors");
631  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
632  status = nc_put_var_float( outfile.gid[1], varid, current_monitors);
633  check_err(status,__LINE__,__FILE__);
634 
635  varname.assign( "CCD_voltages");
636  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
637  status = nc_put_var_float( outfile.gid[1], varid, ccd_voltages);
638  check_err(status,__LINE__,__FILE__);
639 
640  varname.assign( "solenoid_voltage");
641  status = nc_inq_varid( outfile.gid[1], varname.c_str(), &varid);
642  status = nc_put_var_float( outfile.gid[1], varid, solenoid_voltage);
643  check_err(status,__LINE__,__FILE__);
644 
645  // Write image paramter data as attributes
646  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "errorCode",
647  NC_USHORT, 1, &streamInfo.imageInfo.errorCode);
648  check_err(status,__LINE__,__FILE__);
649 
650  status = nc_put_att_uint( outfile.gid[1], NC_GLOBAL, "exposureID",
651  NC_UINT, 1, &streamInfo.imageInfo.exposureID);
652  check_err(status,__LINE__,__FILE__);
653 
654  status = nc_put_att_uint( outfile.gid[1], NC_GLOBAL, "imageID",
655  NC_UINT, 1, &streamInfo.imageInfo.imageID);
656  check_err(status,__LINE__,__FILE__);
657 
658  status = nc_put_att_ulonglong( outfile.gid[1], NC_GLOBAL, "epochT0",
659  NC_UINT64, 1, (const long long unsigned int*)
660  &streamInfo.imageInfo.epochT0);
661  check_err(status,__LINE__,__FILE__);
662 
663  status = nc_put_att_uint( outfile.gid[1], NC_GLOBAL, "hostDeltaEpoch",
664  NC_UINT, 1, &streamInfo.imageInfo.hostDeltaEpoch);
665  check_err(status,__LINE__,__FILE__);
666 
667  status = nc_put_att_uint( outfile.gid[1], NC_GLOBAL, "hawkeyeDeltaEpoch",
668  NC_UINT, 1,
669  &streamInfo.imageInfo.hawkeyeDeltaEpoch);
670  check_err(status,__LINE__,__FILE__);
671 
672  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "spectralBinning",
673  NC_USHORT, 1,
674  &streamInfo.imageInfo.spectralBinning);
675  check_err(status,__LINE__,__FILE__);
676 
677  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "finderscopeBinning",
678  NC_USHORT, 1,
679  &streamInfo.imageInfo.finderscopeBinning);
680  check_err(status,__LINE__,__FILE__);
681 
682  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "channelBitfield",
683  NC_USHORT, 1,
684  &streamInfo.imageInfo.channelBitfield);
685  check_err(status,__LINE__,__FILE__);
686 
687  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "ccd1Exposure",
688  NC_USHORT, 1, &streamInfo.imageInfo.ccd1Exposure);
689  check_err(status,__LINE__,__FILE__);
690 
691  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "ccd2Exposure",
692  NC_USHORT, 1, &streamInfo.imageInfo.ccd2Exposure);
693  check_err(status,__LINE__,__FILE__);
694 
695  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "ccd3Exposure",
696  NC_USHORT, 1, &streamInfo.imageInfo.ccd3Exposure);
697  check_err(status,__LINE__,__FILE__);
698 
699  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "ccd4Exposure",
700  NC_USHORT, 1, &streamInfo.imageInfo.ccd4Exposure);
701  check_err(status,__LINE__,__FILE__);
702 
703  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "height",
704  NC_USHORT, 1, &streamInfo.imageInfo.height);
705  check_err(status,__LINE__,__FILE__);
706 
707  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "darkHeight",
708  NC_USHORT, 1, &streamInfo.imageInfo.darkHeight);
709  check_err(status,__LINE__,__FILE__);
710 
711  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "interval",
712  NC_USHORT, 1, &streamInfo.imageInfo.interval);
713  check_err(status,__LINE__,__FILE__);
714 
715  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "oversampling",
716  NC_USHORT, 1, &streamInfo.imageInfo.oversampling);
717  check_err(status,__LINE__,__FILE__);
718 
719  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "finderscopeExposure",
720  NC_USHORT, 1,
721  &streamInfo.imageInfo.finderscopeExposure);
722  check_err(status,__LINE__,__FILE__);
723 
724  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "noFinderscopeImages",
725  NC_USHORT, 1,
726  &streamInfo.imageInfo.noFinderscopeImages);
727  check_err(status,__LINE__,__FILE__);
728 
729  status = nc_put_att_ubyte( outfile.gid[1], NC_GLOBAL, "compression",
730  NC_UBYTE, 1,
731  (uint8_t *) &streamInfo.imageInfo.compression);
732  check_err(status,__LINE__,__FILE__);
733 
734  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "darkSubtracted",
735  NC_USHORT, 1,
736  &streamInfo.imageInfo.darkSubtracted);
737  check_err(status,__LINE__,__FILE__);
738 
739  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "shutterSolenoid",
740  NC_USHORT, 1,
741  &streamInfo.imageInfo.shutterSolenoid);
742  check_err(status,__LINE__,__FILE__);
743 
744  status = nc_put_att_ushort( outfile.gid[1], NC_GLOBAL, "readoutOrder",
745  NC_USHORT, 1, &streamInfo.imageInfo.readoutOrder);
746  check_err(status,__LINE__,__FILE__);
747 
748  delete[] ( telemetry);
749  delete[] ( tlm_time);
750  delete[] ( tlm_time_stamp);
751  delete[] ( software_version);
752  delete[] ( fpga_version);
753  delete[] ( telemetry_counter);
754  delete[] ( ccd_temperatures);
755  delete[] ( fpga_temperature);
756  delete[] ( fpga_voltages);
757  delete[] ( overcurrent);
758  delete[] ( current_monitors);
759  delete[] ( ccd_voltages);
760  delete[] ( solenoid_voltage);
761 
762  // Date created
763  strcpy( buf, unix2isodate(now(), 'G'));
764  status = nc_put_att_text(outfile.ncid, NC_GLOBAL,
765  "date_created", strlen(buf), buf);
766 
768  double scan_time[MAXIMGHEIGHT];
769  int32_t delta_time[MAXIMGHEIGHT];
770  for (size_t i=0; i<MAXIMGHEIGHT; i++) {
771  scan_time[i] = -999;
772  delta_time[i] = -999;
773  }
774 
775  int varidDark;
776  size_t startDark[3]={0, 0, 0};
777  size_t countDark[3]={1, 1, (size_t) rowOffset-2};
778  status = nc_inq_varid( outfile.gid[3], "band_dark_pixels", &varidDark);
779 
780  for (size_t i=0; i<8; i++) {
781  startDark[0] = i;
782 
783  int hasAverageDark = streamInfo.spectralInfo[i].averageDarkRowPresent;
784 
785  uint16_t imgHeight = streamInfo.spectralInfo[i].height + hasAverageDark;
786 
787  uint16_t imgWidth = 2 + streamInfo.spectralInfo[i].width;
788  uint64_t epochT0 = streamInfo.imageInfo.epochT0;
789  uint32_t pixelLen = imgHeight * imgWidth;
790 
791  // cout << epochT0 << endl;
792 
793  // uint32_t exposure;
794  //if (i / 2 == 0)
795  //exposure = streamInfo.imageInfo.ccd1Exposure * BAND_US_PER_EXPOSURE_COUNT;
796  //else if (i / 2 == 1)
797  //exposure = streamInfo.imageInfo.ccd2Exposure * BAND_US_PER_EXPOSURE_COUNT;
798  //else if (i / 2 == 2)
799  //exposure = streamInfo.imageInfo.ccd3Exposure * BAND_US_PER_EXPOSURE_COUNT;
800  //else
801  //exposure = streamInfo.imageInfo.ccd4Exposure * BAND_US_PER_EXPOSURE_COUNT;
802 
803  uint16_t *pixels = new uint16_t[pixelLen];
804  for ( size_t j=0; j<pixelLen; j++) pixels[j] = 0;
805 
806  HawkeyeDecodeSpectralImage( i, pixels, pixelLen-imgWidth,
807  NULL, imgWidth);
808 
809  size_t start[2]={0, 0};
810  size_t count[2]={1, (size_t) imgWidth-rowOffset};
811 
812  stringstream varstr;
813  varstr << "band_" << setw(1) << i+1;
814  status = nc_inq_varid( outfile.gid[3], varstr.str().c_str(), &varid);
815 
816  cout << "Writing Band: " << (i+1);
817  cout << " Image size: " << imgWidth-rowOffset << " by "
818  << streamInfo.spectralInfo[i].height << endl;
819 
820  // skip band with invalid width read from corrupted raw data, LH, 11/02/2020
821  if (imgWidth>2000) { // normal image width = 1818
822  cout << "Image Width Error in Band " << (i+1) << endl;
823  exit(101);
824  }
825 
826  // Note: Dark row is not written to L1A file
827  for ( size_t j=0; j < (size_t) (imgHeight-1); j++) {
828  if (i == 0) {
829  delta_time[j] = pixels[j*imgWidth]*256*256 + pixels[j*imgWidth+1];
830  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
831  scan_time[j] = epochT0 + delta_time[j];
832  scan_time[j] *= 0.001;
833  scan_time[j] -= (53*24*3600 + 14788.224);
834  tepoch2yds( scan_time[j], &iyr, &idy, &sec);
835  scan_time[j] = sec;
836  if (bImageCrossDay && (sec<80000)) scan_time[j] = sec + 86400.0;
837 
838  if (j == 0 || j == (size_t) (imgHeight-2)) {
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  // cout << time_start << endl;
845  if (j == 0)
846  status = nc_put_att_text(outfile.ncid, NC_GLOBAL,
847  "time_coverage_start", strlen(buf), buf);
848  else
849  status = nc_put_att_text(outfile.ncid, NC_GLOBAL,
850  "time_coverage_end", strlen(buf), buf);
851  }
852  }
853 
854  start[0] = j;
855  status = nc_put_vara_ushort( outfile.gid[3], varid, start, count,
856  &pixels[rowOffset+j*imgWidth]);
857  check_err(status,__LINE__,__FILE__);
858 
859  startDark[1] = j;
860  status = nc_put_vara_ushort( outfile.gid[3], varidDark,
861  startDark, countDark,
862  &pixels[2+j*imgWidth]);
863  check_err(status,__LINE__,__FILE__);
864  }
865  delete[] pixels;
866  } // Band loop
867 
868  varname.assign( "scan_time");
869  status = nc_inq_varid( outfile.gid[0], varname.c_str(), &varid);
870  status = nc_put_var_double( outfile.gid[0], varid, scan_time);
871  check_err(status,__LINE__,__FILE__);
872 
873  varname.assign( "delta_time");
874  status = nc_inq_varid( outfile.gid[0], varname.c_str(), &varid);
875  status = nc_put_var_int( outfile.gid[0], varid, delta_time);
876  check_err(status,__LINE__,__FILE__);
877 
878 
880  //uint16_t finderHeight = FINDERSCOPE_LIGHT_HEIGHT;
881  //uint16_t finderWidth = FINDERSCOPE_LIGHT_WIDTH;
882 
883  uint16_t finderHeight = 0; // streamInfo.finderscopeInfo[0].height; // ver 1.0.1
884  uint16_t finderWidth = 0; // streamInfo.finderscopeInfo[0].width;
885  // find max height and width of finderscope images [MAX_FINDERSCOPE_IMAGES]
886  for (size_t i=0; i<FINDERSCOPE_MAX_IMAGES; i++) {
887  if (streamInfo.finderscopeInfo[i].height > 0) finderHeight = 480;
888  if (streamInfo.finderscopeInfo[i].width > 0) finderWidth = 756;
889  }
890  uint32_t finderPixelLen = finderHeight*finderWidth;
891 
892  if ( finderPixelLen == 0) {
893  cout << "Zero Finder Pixel Length" << endl;
894  outfile.close();
895  return 0;
896  }
897 
898  uint16_t *finderPixels = new uint16_t[finderPixelLen];
899  for (size_t i=0; i<finderPixelLen; i++) finderPixels[i] = 0;
900 
901  size_t start[3]={0, 0, 0};
902  size_t count[3]={1, finderHeight, finderWidth};
903 
904  double finder_time[FINDERSCOPE_MAX_IMAGES];
905  int32_t finder_delta_time[FINDERSCOPE_MAX_IMAGES];
906  uint64_t epochT0 = streamInfo.imageInfo.epochT0;
907 
908  status = nc_inq_varid( outfile.gid[3], "finder", &varid);
909 
910  cout << endl << "Writing Finder Images";
911  cout << " Finder size: " << finderWidth << " by " << finderHeight << endl;
912  int finderScopeStatus;
913  // for (size_t i=0; i< (size_t) streamInfo.noFinderscopeImages; i++) {
914  // There are abnormal cases when finder scope images are stored in sequence as,
915  // [5,6,7,8,9,10,11,15,16,17,18,19,2]
916  for (size_t i=0; i< FINDERSCOPE_MAX_IMAGES; i++) {
917  finder_time[i] = -999;
918  if (streamInfo.finderscopeInfo[i].width==0) continue;
919 
920  finderScopeStatus =
921  HawkeyeDecodeFinderscopeImage(i, finderPixels, finderPixelLen);
922 
923  // if ( finderScopeStatus == HSE_NO_HEADER_FOUND) break;
924  if ( finderScopeStatus == HSE_NO_HEADER_FOUND) continue;
925 
926  // We consolidate the finderPixels buffer by removing the first
927  // n dark pixels from each row and then zeroing out the remaining rows.
928 
929  // for (size_t j=0; j<(752*480/756); j++) {
930  // memmove(&finderPixels[j*FINDERSCOPE_LIGHT_WIDTH],
931  // &finderPixels[j*(FINDERSCOPE_LIGHT_WIDTH+4)+4],
932  // FINDERSCOPE_LIGHT_WIDTH*2);
933  //}
934  //memset(&finderPixels[(752*480/756)*FINDERSCOPE_LIGHT_WIDTH],
935  // 0, (finderPixelLen-(752*480/756)*FINDERSCOPE_LIGHT_WIDTH)*2);
936 
937  start[0] = i;
938  status = nc_put_vara_ushort( outfile.gid[3], varid, start, count,
939  finderPixels);
940  check_err(status,__LINE__,__FILE__);
941 
942  finder_delta_time[i] = streamInfo.finderscopeInfo[i].timeStamp;
943  finder_time[i] = epochT0 + finder_delta_time[i];
944  finder_time[i] *= 0.001;
945  finder_time[i] -= (53*24*3600 + 14788.224);
946  tepoch2yds( finder_time[i], &iyr, &idy, &sec);
947  finder_time[i] = sec;
948  if (bImageCrossDay && (sec<80000)) finder_time[i] = sec + 86400.0;
949 
950  }
951  delete[] finderPixels;
952 
953  if ( finderScopeStatus == HSE_NO_ERROR) {
954  varname.assign( "finder_time");
955  status = nc_inq_varid( outfile.gid[0], varname.c_str(), &varid);
956  status = nc_put_var_double( outfile.gid[0], varid, finder_time);
957  check_err(status,__LINE__,__FILE__);
958 
959  varname.assign( "finder_delta_time");
960  status = nc_inq_varid( outfile.gid[0], varname.c_str(), &varid);
961  status = nc_put_var_int( outfile.gid[0], varid, finder_delta_time);
962  check_err(status,__LINE__,__FILE__);
963  }
964 
966 
967  size_t startNav[2]={0, 0};
968  size_t countNav[2]={1, 1};
969 
970  int offadcs;
971  double min;
972  size_t ngood;
973 
974  // ATTITUDE
975  offadcs = 0;
976  min = attitude[0]->sec;
977  for (size_t i=1; i<n[ATTITUDE]; i++) {
978  // cout << i << " " << attitude[i]->sec << endl;
979  if (attitude[i]->sec < min) {
980  offadcs = i;
981  min = attitude[i]->sec;
982  }
983  }
984 
985  ngood = nSC;
986  for (size_t i=offadcs+1; i<n[ATTITUDE]; i++) {
987  if ((attitude[i]->sec-attitude[i-1]->sec) < 0) {
988  ngood = i - offadcs;
989  break;
990  }
991  }
992  if (ngood > nSC) ngood = nSC;
993  if (n[ATTITUDE] == 0) {
994  ngood = 0; // Set to 0 if no attitude records
995  cout << "No attitude records written" << endl;
996  }
997 
998  varname.assign( "att_time");
999  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1000  for (size_t i=0; i<ngood; i++) {
1001  startNav[0] = i;
1002  status = nc_put_vara_double( outfile.gid[2], varid, startNav, countNav,
1003  &attitude[i+offadcs]->sec);
1004  check_err(status,__LINE__,__FILE__);
1005  }
1006 
1007  varname.assign( "att_quat");
1008  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1009  for (size_t i=0; i<ngood; i++) {
1010  startNav[0] = i;
1011  countNav[1] = 4;
1012  status = nc_put_vara_float( outfile.gid[2], varid, startNav, countNav,
1013  &attitude[i+offadcs]->quat[0]);
1014  check_err(status,__LINE__,__FILE__);
1015  }
1016 
1017  // PROPAGATOR
1018  offadcs = 0;
1019  min = propagator[0]->sec;
1020  for (size_t i=1; i<n[PROPAGATOR]; i++) {
1021  // cout << i << " " << propagator[i]->sec << endl;
1022  if (propagator[i]->sec < min) {
1023  offadcs = i;
1024  min = propagator[i]->sec;
1025  }
1026  }
1027 
1028  ngood = nSC;
1029  for (size_t i=offadcs+1; i<n[PROPAGATOR]; i++) {
1030  if ((propagator[i]->sec-propagator[i-1]->sec) < 0) {
1031  ngood = i - offadcs;
1032  break;
1033  }
1034  }
1035  if (ngood > nSC) ngood = nSC;
1036  if (n[PROPAGATOR] == 0) {
1037  ngood = 0; // Set to 0 if no propagator records
1038  cout << "No progagator records written" << endl;
1039  }
1040 
1041  varname.assign( "orb_time");
1042  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1043  for (size_t i=0; i<ngood; i++) {
1044  startNav[0] = i;
1045  status = nc_put_vara_double( outfile.gid[2], varid, startNav, countNav,
1046  &propagator[i+offadcs]->sec);
1047  check_err(status,__LINE__,__FILE__);
1048  }
1049 
1050  varname.assign( "orb_pos");
1051  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1052  for (size_t i=0; i<ngood; i++) {
1053  startNav[0] = i;
1054  countNav[1] = 3;
1055  status = nc_put_vara_float( outfile.gid[2], varid, startNav, countNav,
1056  &propagator[i+offadcs]->pos[0]);
1057  check_err(status,__LINE__,__FILE__);
1058  }
1059 
1060  varname.assign( "orb_vel");
1061  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1062  for (size_t i=0; i<ngood; i++) {
1063  startNav[0] = i;
1064  countNav[1] = 3;
1065  status = nc_put_vara_float( outfile.gid[2], varid, startNav, countNav,
1066  &propagator[i+offadcs]->vel[0]);
1067  check_err(status,__LINE__,__FILE__);
1068  }
1069 
1070 
1071  // SENSOR
1072  offadcs = 0;
1073  min = sensor[0]->sec;
1074  for (size_t i=1; i<n[SENSOR]; i++) {
1075  // cout << i << " " << sensor[i]->sec << endl;
1076  if (sensor[i]->sec < min) {
1077  offadcs = i;
1078  min = sensor[i]->sec;
1079  }
1080  }
1081 
1082  ngood = nSC;
1083  for (size_t i=offadcs+1; i<n[SENSOR]; i++) {
1084  if ((sensor[i]->sec-sensor[i-1]->sec) < 0) {
1085  ngood = i - offadcs;
1086  break;
1087  }
1088  }
1089  if (ngood > nSC) ngood = nSC; // LH, 7/12/2021
1090  if (ngood > n[SENSOR]) ngood = n[SENSOR]; // LH, 01/15/2021
1091  if (ngood == 0) {
1092  cout << "No sensor records written" << endl;
1093  }
1094 
1095  varname.assign( "sensor_time");
1096  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1097  for (size_t i=0; i<ngood; i++) {
1098  startNav[0] = i;
1099  status = nc_put_vara_double( outfile.gid[2], varid, startNav, countNav,
1100  &sensor[i+offadcs]->sec);
1101  check_err(status,__LINE__,__FILE__);
1102  }
1103 
1104  varname.assign( "sensor_bus_telemetry");
1105  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1106  for (size_t i=0; i<ngood; i++) {
1107  startNav[0] = i;
1108  countNav[1] = 27;
1109  status = nc_put_vara_ubyte( outfile.gid[2], varid, startNav, countNav,
1110  &sensor[i+offadcs]->bus_telemetry[0]);
1111  check_err(status,__LINE__,__FILE__);
1112  }
1113 
1114 
1115  // PSENSOR
1116  offadcs = 0;
1117  min = psensor[0]->sec;
1118  for (size_t i=1; i<n[PSENSOR]; i++) {
1119  // cout << i << " " << psensor[i]->sec << endl;
1120  if (psensor[i]->sec < min) {
1121  offadcs = i;
1122  min = psensor[i]->sec;
1123  }
1124  }
1125 
1126  ngood = nSC;
1127  for (size_t i=offadcs+1; i<n[PSENSOR]; i++) {
1128  if ((psensor[i]->sec-psensor[i-1]->sec) < 0) {
1129  ngood = i - offadcs;
1130  break;
1131  }
1132  }
1133  if (ngood > nSC) ngood = nSC;
1134  if (n[PSENSOR] == 0) {
1135  ngood = 0; // Set to 0 if no psensor records
1136  cout << "No psensor records written" << endl;
1137  }
1138 
1139  varname.assign( "processed_sensor_time");
1140  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1141  for (size_t i=0; i<ngood; i++) {
1142  startNav[0] = i;
1143  status = nc_put_vara_double( outfile.gid[2], varid, startNav, countNav,
1144  &psensor[i+offadcs]->sec);
1145  check_err(status,__LINE__,__FILE__);
1146  }
1147 
1148  varname.assign( "gyro_rates");
1149  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1150  for (size_t i=0; i<ngood; i++) {
1151  startNav[0] = i;
1152  countNav[1] = 3;
1153  status = nc_put_vara_float( outfile.gid[2], varid, startNav, countNav,
1154  &psensor[i+offadcs]->gyro[0]);
1155  check_err(status,__LINE__,__FILE__);
1156  }
1157 
1158  varname.assign( "mag1");
1159  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1160  for (size_t i=0; i<ngood; i++) {
1161  startNav[0] = i;
1162  countNav[1] = 3;
1163  status = nc_put_vara_float( outfile.gid[2], varid, startNav, countNav,
1164  &psensor[i+offadcs]->mag1[0]);
1165  check_err(status,__LINE__,__FILE__);
1166  }
1167 
1168  varname.assign( "mag2");
1169  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1170  for (size_t i=0; i<ngood; i++) {
1171  startNav[0] = i;
1172  countNav[1] = 3;
1173  status = nc_put_vara_float( outfile.gid[2], varid, startNav, countNav,
1174  &psensor[i+offadcs]->mag2[0]);
1175  check_err(status,__LINE__,__FILE__);
1176  }
1177 
1178  varname.assign( "rwheels");
1179  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1180  for (size_t i=0; i<ngood; i++) {
1181  startNav[0] = i;
1182  countNav[1] = 3;
1183  status = nc_put_vara_float( outfile.gid[2], varid, startNav, countNav,
1184  &psensor[i+offadcs]->rwheels[0]);
1185  check_err(status,__LINE__,__FILE__);
1186  }
1187 
1188  varname.assign( "sun_vector");
1189  status = nc_inq_varid( outfile.gid[2], varname.c_str(), &varid);
1190  for (size_t i=0; i<ngood; i++) {
1191  startNav[0] = i;
1192  countNav[1] = 3;
1193  status = nc_put_vara_float( outfile.gid[2], varid, startNav, countNav,
1194  &psensor[i+offadcs]->sunb[0]);
1195  check_err(status,__LINE__,__FILE__);
1196  }
1197 
1198  outfile.close();
1199 
1200  return 0;
1201 }
1202 
1203 
1204 /*----------------------------------------------------------------- */
1205 /* Create an Generic NETCDF4 level1 file */
1206 /* ---------------------------------------------------------------- */
1207 int l1aFile::createl1( char* l1_filename, uint32_t nSC,
1208  uint32_t imgWidth, uint32_t imgHeight,
1209  uint32_t fndWidth, uint32_t fndHeight) {
1210 
1211  int status;
1212 
1213  status = nc_create( l1_filename, NC_NETCDF4, &ncid);
1214  check_err(status,__LINE__,__FILE__);
1215 
1216  ifstream hawkeye_l1a_data_structure;
1217  string line;
1218  string dataStructureFile;
1219 
1220  dataStructureFile.assign("$OCDATAROOT/hawkeye/Hawkeye_Level-1A_Data_Structure.cdl");
1221  expandEnvVar( &dataStructureFile);
1222 
1223  hawkeye_l1a_data_structure.open( dataStructureFile.c_str(), ifstream::in);
1224  if ( hawkeye_l1a_data_structure.fail() == true) {
1225  cout << "\"" << dataStructureFile.c_str() << "\" not found" << endl;
1226  exit(1);
1227  }
1228 
1229  // Find "dimensions" section of CDL file
1230  while(1) {
1231  getline( hawkeye_l1a_data_structure, line);
1232  size_t pos = line.find("dimensions:");
1233  if ( pos == 0) break;
1234  }
1235 
1236  // Define dimensions from "dimensions" section of CDL file
1237  ndims = 0;
1238  //int32_t numScans=0;
1239  while(1) {
1240  getline( hawkeye_l1a_data_structure, line);
1241  size_t pos = line.find(" = ");
1242  if ( pos == string::npos) break;
1243 
1244  uint32_t dimSize;
1245  istringstream iss(line.substr(pos+2, string::npos));
1246  iss >> dimSize;
1247 
1248  iss.clear();
1249  iss.str( line);
1250  iss >> skipws >> line;
1251 
1252  // cout << "Dimension Name: " << line.c_str() << " Dimension Size: "
1253  // << dimSize << endl;
1254 
1255  //if (line.compare("number_of_scans") == 0 && numScans > 0) {
1256  // dimSize = numScans;
1257  //}
1258 
1259  if (line.compare("number_of_SC_records") == 0) {
1260  dimSize = nSC;
1261  }
1262 
1263  if (line.compare("number_of_scans") == 0) {
1264  dimSize = imgHeight;
1265  }
1266 
1267  if (line.compare("number_of_pixels") == 0) {
1268  dimSize = imgWidth;
1269  }
1270 
1271  if (line.compare("finder_lines") == 0) {
1272  dimSize = fndHeight;
1273  }
1274 
1275  if (line.compare("finder_pixels") == 0) {
1276  dimSize = fndWidth;
1277  }
1278 
1279  status = nc_def_dim( ncid, line.c_str(), dimSize, &dimid[ndims++]);
1280  check_err(status,__LINE__,__FILE__);
1281 
1282  } // while loop
1283 
1284  // Read global attributes (string attributes only)
1285  while(1) {
1286  getline( hawkeye_l1a_data_structure, line);
1287  size_t pos = line.find("// global attributes");
1288  if ( pos == 0) break;
1289  }
1290 
1291  while(1) {
1292  getline( hawkeye_l1a_data_structure, line);
1293  size_t pos = line.find(" = ");
1294  if ( pos == string::npos) break;
1295 
1296  string attValue;
1297 
1298  // Remove leading and trailing quotes
1299  attValue.assign(line.substr(pos+4));
1300  size_t posQuote = attValue.find("\"");
1301  attValue.assign(attValue.substr(0, posQuote));
1302 
1303  istringstream iss(line.substr(pos+2));
1304  iss.clear();
1305  iss.str( line);
1306  iss >> skipws >> line;
1307 
1308  // Skip commented out attributes
1309  if (line.compare("//") == 0) continue;
1310 
1311  string attName;
1312  attName.assign(line.substr(1).c_str());
1313 
1314  // Skip non-string attributes
1315  if (attName.compare("orbit_number") == 0) continue;
1316  if (attName.compare("history") == 0) continue;
1317  if (attName.compare("format_version") == 0) continue;
1318  if (attName.compare("instrument_number") == 0) continue;
1319  if (attName.compare("pixel_offset") == 0) continue;
1320  if (attName.compare("number_of_filled_scans") == 0) continue;
1321 
1322  // cout << attName.c_str() << " " << attValue.c_str() << endl;
1323 
1324  status = nc_put_att_text(ncid, NC_GLOBAL, attName.c_str(),
1325  strlen(attValue.c_str()), attValue.c_str());
1326  check_err(status,__LINE__,__FILE__);
1327 
1328  } // while(1)
1329 
1330 
1331  ngrps = 0;
1332  // Loop through groups
1333  while(1) {
1334  getline( hawkeye_l1a_data_structure, line);
1335 
1336  // Check if end of CDL file
1337  // If so then close CDL file and return
1338  if (line.substr(0,1).compare("}") == 0) {
1339  hawkeye_l1a_data_structure.close();
1340  return 0;
1341  }
1342 
1343  // Check for beginning of new group
1344  size_t pos = line.find("group:");
1345 
1346  // If found then create new group and variables
1347  if ( pos == 0) {
1348 
1349  // Parse group name
1350  istringstream iss(line.substr(6, string::npos));
1351  iss >> skipws >> line;
1352 
1353  // Create NCDF4 group
1354  status = nc_def_grp( ncid, line.c_str(), &gid[ngrps]);
1355  check_err(status,__LINE__,__FILE__);
1356 
1357  ngrps++;
1358 
1359  int numDims=0;
1360  int varDims[NC_MAX_DIMS];
1361  size_t dimSize[NC_MAX_DIMS];
1362  char dimName[NC_MAX_NAME+1];
1363  string sname;
1364  string lname;
1365  string standard_name;
1366  string units;
1367  string flag_values;
1368  string flag_meanings;
1369  double valid_min=0.0;
1370  double valid_max=0.0;
1371  double fill_value=0.0;
1372  float scale_factor=1.0;
1373  float add_offset=0.0;
1374 
1375  int ntype=0;
1376 
1377  // Loop through datasets in group
1378  getline( hawkeye_l1a_data_structure, line); // skip "variables:"
1379  while(1) {
1380  getline( hawkeye_l1a_data_structure, line);
1381 
1382  if (line.length() == 0) continue;
1383  if (line.substr(0,1).compare("\r") == 0) continue;
1384  if (line.substr(0,1).compare("\n") == 0) continue;
1385 
1386  size_t pos = line.find(":");
1387 
1388  // No ":" found, new dataset or empty line or end-of-group
1389  if ( pos == string::npos) {
1390 
1391  if ( numDims > 0) {
1392  // Create previous dataset
1393  createNCDF( gid[ngrps-1],
1394  sname.c_str(), lname.c_str(),
1395  standard_name.c_str(), units.c_str(),
1396  (void *) &fill_value,
1397  flag_values.c_str(), flag_meanings.c_str(),
1398  valid_min, valid_max, scale_factor, add_offset, ntype, numDims, varDims);
1399 
1400  flag_values.assign("");
1401  flag_meanings.assign("");
1402  units.assign("");
1403  }
1404 
1405  valid_min=0.0;
1406  valid_max=0.0;
1407  fill_value=0.0;
1408 
1409  if (line.substr(0,10).compare("} // group") == 0) break;
1410 
1411  // Parse variable type
1412  string varType;
1413  istringstream iss(line);
1414  iss >> skipws >> varType;
1415 
1416  // Get corresponding NC variable type
1417  if ( varType.compare("char") == 0) ntype = NC_CHAR;
1418  else if ( varType.compare("byte") == 0) ntype = NC_BYTE;
1419  else if ( varType.compare("short") == 0) ntype = NC_SHORT;
1420  else if ( varType.compare("int") == 0) ntype = NC_INT;
1421  else if ( varType.compare("long") == 0) ntype = NC_INT;
1422  else if ( varType.compare("float") == 0) ntype = NC_FLOAT;
1423  else if ( varType.compare("real") == 0) ntype = NC_FLOAT;
1424  else if ( varType.compare("double") == 0) ntype = NC_DOUBLE;
1425  else if ( varType.compare("ubyte") == 0) ntype = NC_UBYTE;
1426  else if ( varType.compare("ushort") == 0) ntype = NC_USHORT;
1427  else if ( varType.compare("uint") == 0) ntype = NC_UINT;
1428  else if ( varType.compare("int64") == 0) ntype = NC_INT64;
1429  else if ( varType.compare("uint64") == 0) ntype = NC_UINT64;
1430 
1431  // Parse short name (sname)
1432  pos = line.find("(");
1433  size_t posSname = line.substr(0, pos).rfind(" ");
1434  sname.assign(line.substr(posSname+1, pos-posSname-1));
1435  //cout << "sname: " << sname.c_str() << endl;
1436 
1437  // Parse variable dimension info
1438  this->parseDims( line.substr(pos+1, string::npos),
1439  &numDims, varDims);
1440  for (int i=0; i<numDims; i++) {
1441  nc_inq_dim( ncid, varDims[i], dimName, &dimSize[i]);
1442  //cout << line.c_str() << " " << i << " " << dimName
1443  // << " " << dimSize[i] << endl;
1444  }
1445 
1446  } else {
1447  // Parse variable attributes
1448  size_t posEql = line.find("=");
1449  size_t pos1qte = line.find("\"");
1450  size_t pos2qte = line.substr(pos1qte+1, string::npos).find("\"");
1451  // cout << line.substr(pos+1, posEql-pos-2).c_str() << endl;
1452 
1453  string attrName = line.substr(pos+1, posEql-pos-2);
1454 
1455  // Get long_name
1456  if ( attrName.compare("long_name") == 0) {
1457  lname.assign(line.substr(pos1qte+1, pos2qte));
1458  // cout << "lname: " << lname.c_str() << endl;
1459  }
1460 
1461  // Get units
1462  else if ( attrName.compare("units") == 0) {
1463  units.assign(line.substr(pos1qte+1, pos2qte));
1464  // cout << "units: " << units.c_str() << endl;
1465  }
1466 
1467  // Get _FillValue
1468  else if ( attrName.compare("_FillValue") == 0) {
1469  iss.clear();
1470  iss.str( line.substr(posEql+1, string::npos));
1471  iss >> fill_value;
1472  // cout << "_FillValue: " << fill_value << endl;
1473  }
1474 
1475  // Get flag_values
1476  else if ( attrName.compare("flag_values") == 0) {
1477  flag_values.assign(line.substr(pos1qte+1, pos2qte));
1478  }
1479 
1480  // Get flag_meanings
1481  else if ( attrName.compare("flag_meanings") == 0) {
1482  flag_meanings.assign(line.substr(pos1qte+1, pos2qte));
1483  }
1484 
1485  // Get valid_min
1486  else if ( attrName.compare("valid_min") == 0) {
1487  iss.clear();
1488  iss.str( line.substr(posEql+1, string::npos));
1489  iss >> valid_min;
1490  // cout << "valid_min: " << valid_min << endl;
1491  }
1492 
1493  // Get valid_max
1494  else if ( attrName.compare("valid_max") == 0) {
1495  iss.clear();
1496  iss.str( line.substr(posEql+1, string::npos));
1497  iss >> valid_max;
1498  // cout << "valid_max: " << valid_max << endl;
1499  }
1500 
1501  } // if ( pos == string::npos)
1502  } // datasets in group loop
1503  } // New Group loop
1504  } // Main Group loop
1505 
1506  return 0;
1507 }
1508 
1509 
1510 int l1aFile::parseDims( string dimString, int *numDims, int *varDims) {
1511 
1512  size_t dimSize, curPos=0;
1513  char dimName[NC_MAX_NAME+1];
1514 
1515  *numDims = 0;
1516 
1517  while(1) {
1518  size_t pos = dimString.find(",", curPos);
1519  if ( pos == string::npos)
1520  pos = dimString.find(")");
1521 
1522  string varDimName;
1523  istringstream iss(dimString.substr(curPos, pos-curPos));
1524  iss >> skipws >> varDimName;
1525 
1526  for (int i=0; i<ndims; i++) {
1527  int status = nc_inq_dim( ncid, dimid[i], dimName, &dimSize);
1528  check_err(status,__LINE__,__FILE__);
1529  if ( varDimName.compare(dimName) == 0) {
1530  varDims[(*numDims)++] = dimid[i];
1531  break;
1532  }
1533  }
1534  if ( dimString.substr(pos, 1).compare(")") == 0) break;
1535 
1536  curPos = pos + 1;
1537  }
1538 
1539  return 0;
1540 }
1541 
1542 
1544 
1545  int status = nc_close(ncid);
1546 
1547  if (status != NC_NOERR)
1548  {
1549  printf("-E - nc_close failed for ncid: %i\n",ncid);
1550  }
1551  return 0;
1552 }
1553 
1554 
1555 int unpack_seahawk_adcs( uint8_t *apkt, double startHWKTime, double stopHWKTime,
1556  sensor_t *sensor, psensor_t *psensor,
1557  attitude_t *attitude, propagator_t *propagator) {
1558 
1559  int16_t i16;
1560  int32_t i32;
1561  int32_t iyr, idy;
1562  int32_t startdy, stopdy;
1563  double sec;
1564 
1565  short psub = apkt[8];
1566 
1567  // Get time
1568 
1569  // JD 2015/01/01 = 2457023.5
1570  // JD 1980/01/06 = 2444244.5
1571  // delta sec = (2457023.5-2444244.5) * 24 * 3600 = 1104105600
1572  // Add 16 leapsecs between 1980/01/06 and 2015/01/01
1573 
1574  memcpy(&i32, &apkt[9], 4);
1575  double tepoch = (double) __builtin_bswap32(i32) - (1104105600+16);
1576 
1577  // cout << tepoch - startHWKTime << endl;
1578  if ( (startHWKTime-tepoch) > 2 || (tepoch - stopHWKTime) > 1) {
1579  return -1;
1580  }
1581 
1582  tepoch2yds( startHWKTime, &iyr, &idy, &sec);
1583  startdy = iyr*1000 + idy;
1584  tepoch2yds( stopHWKTime, &iyr, &idy, &sec);
1585  stopdy = iyr*1000 + idy;
1586 
1587  tepoch2yds( tepoch, &iyr, &idy, &sec);
1588  memcpy(&i32, &apkt[13], 4);
1589  sec += ((double) __builtin_bswap32(i32)) / 4294967296.0;
1590  memcpy(&i16, &apkt[17], 2);
1591  sec -= ((double) SWAP_2(i16)) / 1000;
1592  // if the image spans over 00:00, the sec of day for earlier part of image is from previous day,
1593  // ending with a value close to 86400
1594  if ((stopdy>startdy) && (sec<80000)) sec += 86400.0;
1595 
1596  switch (psub) {
1597  case 1:
1598  sensor->iyr = iyr;
1599  sensor->iday = idy;
1600  sensor->sec = sec;
1601  memcpy(sensor->bus_telemetry, &apkt[19], sizeof(sensor->bus_telemetry));
1602  break;
1603 
1604  case 2:
1605  psensor->iyr = iyr;
1606  psensor->iday = idy;
1607  psensor->sec = sec;
1608  for (size_t i=0; i<3; i++) {
1609  memcpy(&i32, &apkt[19+4*i], 4);
1610  i32 = __builtin_bswap32(i32);
1611  memcpy(&psensor->gyro[i], &i32, 4);
1612 
1613  memcpy(&i32, &apkt[31+4*i], 4);
1614  i32 = __builtin_bswap32(i32);
1615  memcpy(&psensor->mag1[i], &i32, 4);
1616 
1617  memcpy(&i32, &apkt[43+4*i], 4);
1618  i32 = __builtin_bswap32(i32);
1619  memcpy(&psensor->mag2[i], &i32, 4);
1620 
1621  memcpy(&i32, &apkt[55+4*i], 4);
1622  i32 = __builtin_bswap32(i32);
1623  memcpy(&psensor->rwheels[i], &i32, 4);
1624 
1625  memcpy(&i32, &apkt[67+4*i], 4);
1626  i32 = __builtin_bswap32(i32);
1627  memcpy(&psensor->sunb[i], &i32, 4);
1628  }
1629  break;
1630 
1631  case 3:
1632  attitude->iyr = iyr;
1633  attitude->iday = idy;
1634  attitude->sec = sec;
1635  for (size_t i=0; i<4; i++) {
1636  memcpy(&i32, &apkt[19+4*i], 4);
1637  i32 = __builtin_bswap32(i32);
1638  memcpy(&attitude->quat[i], &i32, 4);
1639  }
1640  break;
1641 
1642  case 4:
1643  propagator->iyr = iyr;
1644  propagator->iday = idy;
1645  propagator->sec = sec;
1646  for (size_t i=0; i<3; i++) {
1647  memcpy(&i32, &apkt[19+4*i], 4);
1648  i32 = __builtin_bswap32(i32);
1649  memcpy(&propagator->pos[i], &i32, 4);
1650 
1651  memcpy(&i32, &apkt[31+4*i], 4);
1652  i32 = __builtin_bswap32(i32);
1653  memcpy(&propagator->vel[i], &i32, 4);
1654  }
1655  break;
1656  }
1657 
1658  return 0;
1659 }
1660 
1661 
@ TC_FPGA_VERSION
Definition: Hawkeye.h:91
uint16_t spectralBinning
Definition: HawkeyeDecode.h:53
@ TC_CCD4_TEMP
Definition: Hawkeye.h:92
void interp(double *ephemPtr, int startLoc, double *inTime, int numCoefs, int numCom, int numSets, int velFlag, double *posvel)
int32 value
Definition: Granule.c:1235
int gid[10]
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)
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
int expandEnvVar(string *sValue)
Definition: hawkeyeUtil.h:41
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
Definition: orbit.h:79
int16_t iyr
@ TC_AD7490_CH06
Definition: Hawkeye.h:93
int count
Definition: decode_rs.h:79