NASA Logo
Ocean Color Science Software

ocssw V2022
l0gen_hawkeye.cpp
Go to the documentation of this file.
1 #include <stdint.h>
2 #include <libgen.h>
3 #include <iostream>
4 #include <fstream>
5 #include <sstream>
6 #include <string>
7 #include <iomanip>
8 #include <getopt.h>
9 
10 #include "hawkeyeUtil.h"
11 
12 #define VERSION "1.0.0_2023-05-10"
13 
14 // Modification history:
15 // Programmer Organization Date Ver Description of change
16 // ---------- ------------ ---- --- ---------------------
17 // Joel Gales FutureTech 08/08/18 0.10 Original development
18 // Joel Gales FutureTech 08/30/18 0.11 Output L0 filenames generated
19 // from image start time, Add
20 // support for text output files
21 //
22 // Joel Gales FutureTech 09/20/18 0.20 Add duration to textfile,
23 // generate output name from
24 // starttime
25 // Joel Gales FutureTech 09/27/18 0.30 Add Start/Stop HWK time to
26 // textfile (Delete duration).
27 // Pass through StartTime code
28 // only once.
29 // Joel Gales SAIC 10/26/18 0.40 Code cleanup, Prepend tlm
30 // filename, exposure ID, and
31 // image counter to HWK L0 name
32 // Joel Gales SAIC 11/16/18 0.50 Add support for GPS telemetry
33 // output telemetry file
34 // Joel Gales SAIC 03/07/19 0.55 Fix error in last L0 outfile
35 // name
36 // Joel Gales SAIC 05/23/19 0.60 Overhaul to handle frame drops
37 // Joel Gales SAIC 06/19/19 0.70 Force new frame read if bad
38 // packet header
39 // Joel Gales SAIC 07/09/19 0.71 Trap negative dataLen
40 // filename
41 // Joel Gales SAIC 07/29/19 0.80 Trap bad framePtr value in
42 // getSHpacket. Check for
43 // output filesize
44 // Liang Hong SAIC 07/13/21 0.82 Handle EOI packet crossing frames
45 // Liang Hong SAIC 08/06/21 0.83 Handle missing EOI packet images
46 // Liang Hong SAIC 08/12/21 0.84 Updated frame pointer initialization,
47 // packet reading, and EOI detections
48 // Liang Hong SAIC 09/01/21 0.85 Updated End of Exposure detection
49 // Liang Hong SAIC 05/10/23 1.00 Add verbose option
50 
51 using namespace std;
52 
53 #define DATAFRAMEBYTES 892
54 
55 int getZuluTime_L0Name( double tlm_time,
56  string *zuluTime, string *packetOutName);
57 
58 #define SWAP_2(x) ( (((x) & 0xff) << 8) | ((unsigned short)(x) >> 8) )
59 
60 int main (int argc, char* argv[])
61 {
62  cout << "l0gen_hawkeye " << VERSION << " ("
63  << __DATE__ << " " << __TIME__ << ")" << endl;
64 
65  if ( argc == 1) {
66  cout << endl <<
67  "l0gen_hawkeye_new input_telemetry_filename" << endl;
68 
69  return 0;
70  }
71 
72  ifstream framefile;
73  framefile.open( argv[1], ios::binary );
74  // int lastpos = framefile.tellg();
75 
76  bool isVerbose = false;
77  int c;
78  while (1) {
79  static struct option long_options[] = {
80  {"Verbose", no_argument,0,'v'}
81  };
82 
83  /* getopt_long stores the option index here. */
84  int option_index = 0;
85 
86  c = getopt_long( argc, argv, "v", long_options, &option_index);
87 
88  /* Detect the end of the options. */
89  if (c == -1)
90  break;
91 
92  switch (c)
93  {
94  case 'v':
95  isVerbose = true;
96  break;
97 
98  default:
99  abort ();
100  }
101  }
102 
103  ofstream packetOut;
104  ofstream gpsOut;
105  ofstream textOut;
106 
107  string packetOutname="TBD";
108  string zuluStartTime, zuluStopTime;
109  string prePend;
110 
111  double startHWKTime=0.0;
112  double stopHWKTime=0.0;
113 
114  uint32_t exposureID;
115  //uint32_t deltaTime;
116  //uint32_t imageRow;
117  //uint32_t finderNumber;
118 
119  uint32_t prevExposureID=999999999;
120  //uint32_t prevRow;
121  //uint32_t prevFinder;
122  //int prevDeltaTime;
123 
124  int packetLength;
125 
126  // get length of input framefile:
127  // framefile.seekg (0, ios::end);
128  // uint32_t granuleLength = framefile.tellg();
129  // framefile.seekg (0, ios::beg);
130 
131  uint8_t **packet = new uint8_t*;
132 
133  // int write=0;
134  int firstGPS=1;
135 
136  // int imageCounter=0;
137 
138  uint8_t frame[DATAFRAMEBYTES];
139 
140  // Skip fill records and find first good packet
141  int framePtr = 2046;
142  while (framePtr == 2046 || framePtr == 2047) {
143  framefile.read( (char *) frame, DATAFRAMEBYTES);
144  framePtr = (frame[4] % 8)*256 + frame[5];
145  }
146  framePtr += 6;
147 
148  int frameDrop = 0;
149 
150  int prevFrameCnt = frame[2];
151 
152  // int framePtr = 6;
153 
154  // packet[7]
155  // ---------
156  // 253 -- Image data
157  // 254 -- GPS data
158  // 255 -- ADCS data
159 
160  // Image Data (packet[8])
161  // ----------
162  // 1 -- Uncompressed Image Data
163  // 2 -- Compressed Image Data
164  // 3 -- Image parameters
165  // 4 -- Telemetry
166  // 5 -- End of File
167  // 6 -- Mission Log
168 
169  packetOut.open("tempL0_0", ios::out | ios::trunc | ios::binary);
170  int tempCnt = 0;
171  int exposureCount = 0;
172  while (1) {
173  frameDrop = 0; // V0.84
174 
175  int result_getSHpacket = getSHpacket( &framefile, frame, framePtr, packet, packetLength,
176  prevFrameCnt, frameDrop, isVerbose);
177 
178  // V0.82, End of exposure packet detected at frame boundary
179  if (result_getSHpacket==1){
180  cout<<"exposureID="<<exposureID<<endl;
181  cout << "end of exposure" << endl;
182  packetOut.close();
183 
184  tempCnt++;
185  string tempName;
186  tempName.assign("tempL0_");
187  tempName.append(to_string(tempCnt));
188  packetOut.open(tempName.c_str(), ios::out | ios::trunc | ios::binary);
189 
190  //prevRow = 0;
191  //prevFinder = 0;
192 
193  framefile.read( (char *) frame, DATAFRAMEBYTES);
194 
195  // int priPacketLen = (frame[4] % 8) * 256 + frame[5];
196  framePtr = (frame[4] % 8) * 256 + frame[5];
197  while (framePtr == 2046 || framePtr == 2047) {
198  framefile.read( (char *) frame, DATAFRAMEBYTES);
199  framePtr = (frame[4] % 8) * 256 + frame[5];
200  }
201  prevFrameCnt = frame[2];
202  framePtr += 6; // V0.84
203  prevExposureID = 999999999;
204  continue;
205  } else {
206  if (frameDrop == -1) continue;
207 
208  long long int pos = framefile.tellg();
209  // cout << "pos: " << pos << endl;
210  if ( framefile.eof() || pos == -1) break;
211 
212  // frame drop
213  if (frameDrop == 1) {
214  frameDrop = 2;
215  continue;
216  }
217 
218  if ((frame[4] % 8)*256 + frame[5] == 2046) {
219  continue;
220  }
221  }
222 
226  //int apid = ((*packet)[0] % 8) * 256 + (*packet)[1]; // V0.85
227  //if (apid == 2047) { // V0.85
228  if ((*packet)[0]==7 && (*packet)[1]==255) { // updated End of Exposure detection, V0.85
229  cout<<"exposureID="<<exposureID<<endl; // V0.82
230  cout << "end of exposure" << endl;
231  packetOut.close();
232 
233  tempCnt++;
234  string tempName;
235  tempName.assign("tempL0_");
236  tempName.append(to_string(tempCnt));
237  packetOut.open(tempName.c_str(), ios::out | ios::trunc | ios::binary);
238 
239  //prevRow = 0;
240  //prevFinder = 0;
241 
242  framefile.read( (char *) frame, DATAFRAMEBYTES);
243 
244  // int priPacketLen = (frame[4] % 8) * 256 + frame[5];
245  framePtr = (frame[4] % 8) * 256 + frame[5];
246  while (framePtr == 2046 || framePtr == 2047) {
247  framefile.read( (char *) frame, DATAFRAMEBYTES);
248  framePtr = (frame[4] % 8) * 256 + frame[5];
249  }
250  prevFrameCnt = frame[2];
251  framePtr += 6; // V0.84
252  prevExposureID = 999999999;
253  continue;
254  }
255 
256 
260  if ((*packet)[7] == 253 && (*packet)[8] == 3) {
261 
262  uint64_t ll;
263  uint32_t ul;
264 
265  // Decode Exposure ID
266  ul = (uint32_t) (*packet)[15] << 24;
267  ul += (uint32_t) (*packet)[16] << 16;
268  ul += (uint32_t) (*packet)[17] << 8;
269  ul += (*packet)[18];
270  exposureID = ul;
271  cout<<"read exposureID="<<exposureID<<endl;
272 
273  // Decode Epoch Time
274  // Code taken from DecodeImageParams() in HawkeyeDecode.c
275  ll = (uint64_t) (*packet)[26] << 40;
276  ll += (uint64_t) (*packet)[27] << 32;
277  ll += (uint64_t) (*packet)[28] << 24;
278  ll += (uint64_t) (*packet)[29] << 16;
279  ll += (uint64_t) (*packet)[30] << 8;
280  ll += (*packet)[31];
281  ll = (ll & 0x0FFFFFFFFFF0) >> 4;
282 
283  // double tlm_time;
284 
285  //tlm_time = ll * 0.001;
286  //tlm_time -= (53*24*3600 + 14788.224);
287  //cout << "imag tepoch: " << setprecision(11) << setw(15) << tlm_time << endl;
288 
289  if (exposureID<310000000 && exposureID>180000000) { // V0.85, avoid bogus exposure id
290  //if (frameDrop == 2) {
291  if (prevExposureID != 999999999 && prevExposureID != exposureID) frameDrop = 3;
292  //}
293  prevExposureID = exposureID;
294  }
295  }
296 
297 
301  if ((*packet)[7] == 253 && (*packet)[8] == 2) {
302  uint16_t row;
303  memcpy(&row, &(*packet)[20], 2);
304  row = SWAP_2(row);
305 
306  //uint8_t infoByte = (*packet)[15];
307  //uint8_t sb = infoByte & 0x1f;
308 
309  // sd_f: 0 - finder, 1 - spectral (image)
310  //uint8_t sd_f = (infoByte & 0x40) >> 6;
311  // uint8_t dark = (infoByte & 0x80) >> 7;
312 
313  //uint32_t ul;
314 
315  //Decode Delta-Hawkeye time
316  //ul = (uint32_t) (*packet)[16] << 24;
317  //ul += (uint32_t) (*packet)[17] << 16;
318  //ul += (uint32_t) (*packet)[18] << 8;
319  //ul += (*packet)[19];
320  //deltaTime = (ul >> 4) & 0xFFFFFF;
321 
322 /* V0.84
323  if (frameDrop == 2) {
324  if (sd_f == 1 && row < prevRow)
325  frameDrop = 3;
326  if (sd_f == 0 && sb < prevFinder)
327  frameDrop = 3;
328  // if (sd_f == 1 && (((int) deltaTime) - prevDeltaTime) > 100*1000)
329  // frameDrop = 3;
330  }
331 
332  if (sd_f == 1) {
333  // cout << "band, row: " << (int) sb << " " << (int) row << endl;
334  prevRow = row;
335  } else {
336  //cout << "find, row: " << (int) sb << " " << (int) row << endl;
337  prevFinder = sb;
338  }
339  //if (sd_f == 1) prevDeltaTime = deltaTime;
340 */
341 
342  }
343 
344 
348  if ((*packet)[7] == 254) {
349 
350  // cout << "GPS Packet" << (int) (*packet)[8] << " " << packetLength << endl;
351 
352  if (firstGPS) {
353  string gpsName;
354  gpsName.assign(basename(argv[1]));
355  size_t strpos = gpsName.find(".tlm");
356  gpsName = gpsName.substr(0, strpos);
357  gpsName.append(".gps");
358 
359  gpsOut.open(gpsName.c_str(), ios::out | ios::trunc | ios::binary);
360  firstGPS = 0;
361  }
362 
363  gpsOut.write( (char *) &(*packet)[0], 161);
364 
365 
369  } else if ((*packet)[7] == 255) {
370  // ADCS packet
371  // cout << "ADCS packet: " << (int) (*packet)[3] << " " <<
372  // (int) (*packet)[8] << " " << packetLength << endl;
373 
374 
375  int16_t i16;
376  int32_t i32;
377  int32_t iyr, idy;
378  double sec;
379 
380  // Get time
381 
382  // JD 2015/01/01 = 2457023.5
383  // JD 1980/01/06 = 2444244.5
384  // delta sec = (2457023.5-2444244.5) * 24 * 3600 = 1104105600
385  // Add 16 leapsecs between 1980/01/06 and 2015/01/01
386 
387  memcpy(&i32, &(*packet)[9], 4);
388  double tepoch = (double) __builtin_bswap32(i32) - (1104105600+16);
389  // cout << "adcs tepoch: " << setprecision(11) << setw(20) << tepoch << endl;
390  tepoch2yds( tepoch, &iyr, &idy, &sec);
391  memcpy(&i32, &(*packet)[13], 4);
392  sec += ((double) __builtin_bswap32(i32)) / 4294967296.0;
393  memcpy(&i16, &(*packet)[17], 2);
394  sec -= ((double) SWAP_2(i16)) / 1000;
395  //cout << "adcs sec: " << sec << endl;
396  }
397 
398 
399  if ( frameDrop == 3) {
400  packetOut.close();
401  cout<<"exposureID="<<exposureID<<endl; // V0.82
402  cout << "Close image file" << endl; // V0.82
403 
404  tempCnt++;
405  string tempName;
406  tempName.assign("tempL0_");
407  tempName.append(to_string(tempCnt));
408 
409  packetOut.open(tempName.c_str(), ios::out | ios::trunc | ios::binary);
410 
411  //prevRow = 0;
412  //prevFinder = 0;
413 
414  frameDrop = 0;
415  // prevExposureID = 999999999; V0.85
416  }
417 
418 
419  if ((*packet)[7] != 0) {
420  packetOut.write( (char *) (*packet), packetLength);
421  delete[] (*packet);
422  }
423  } // end main loop
424 
425  delete packet;
426 
427  tempCnt++;
428  for (int i=0; i<tempCnt; i++) {
429  string tempName;
430  tempName.assign("tempL0_");
431  tempName.append(to_string(i));
432 
433  ifstream tempFile;
434  uint8_t sndpus[9];
435  uint8_t *data;
436 
437  tempFile.open( tempName.c_str(), ios::binary );
438 
439  // Check file size -- Skip if 4503 bytes
440  int fsize = tempFile.tellg();
441  tempFile.seekg( 0, std::ios::end);
442  fsize = (int) tempFile.tellg() - fsize;
443  // cout << fsize << endl;
444  if ( fsize == 4503 || fsize <= 10000000) {
445  remove( tempName.c_str());
446  continue;
447  }
448 
449  tempFile.seekg( 0, std::ios::beg);
450 
451  while (!tempFile.eof()) {
452  tempFile.read( (char *) sndpus, 9);
453  int datalen = sndpus[4]*256 + sndpus[5] - 2;
454  data = new uint8_t[datalen];
455  tempFile.read( (char *) data, datalen);
456 
457  if (sndpus[7] == 253 && sndpus[8] == 3) {
458  // Parameter Packet
459 
460  uint64_t ll;
461  uint32_t ul;
462 
463  // Decode Exposure ID
464  ul = (uint32_t) data[15-9] << 24;
465  ul += (uint32_t) data[16-9] << 16;
466  ul += (uint32_t) data[17-9] << 8;
467  ul += data[18-9];
468  exposureID = ul;
469 
470  // Decode Epoch Time
471  // Code taken from DecodeImageParams() in HawkeyeDecode.c
472  ll = (uint64_t) data[26-9] << 40;
473  ll += (uint64_t) data[27-9] << 32;
474  ll += (uint64_t) data[28-9] << 24;
475  ll += (uint64_t) data[29-9] << 16;
476  ll += (uint64_t) data[30-9] << 8;
477  ll += data[31-9];
478  ll = (ll & 0x0FFFFFFFFFF0) >> 4;
479 
480  //Decode Delta-Hawkeye time
481  ul = (uint32_t) data[36-9] << 24;
482  ul += (uint32_t) data[37-9] << 16;
483  ul += (uint32_t) data[38-9] << 8;
484  ul += data[39-9];
485  ul = (ul >> 4) & 0xFFFFFF;
486 
487  double tlm_time;
488 
489  tlm_time = ll * 0.001;
490  tlm_time -= (53*24*3600 + 14788.224);
491  getZuluTime_L0Name( tlm_time, &zuluStartTime, &packetOutname);
492  startHWKTime = tlm_time;
493 
494  tlm_time = (ll + ul) * 0.001;
495  tlm_time -= (53*24*3600 + 14788.224);
496  getZuluTime_L0Name( tlm_time, &zuluStopTime, NULL);
497  stopHWKTime = tlm_time;
498 
499  break;
500  // Note HWK time is seconds from 2015/01/01
501  }
502  }
503  tempFile.close();
504 
505  // Generate prePend
506  prePend.assign(basename(argv[1]));
507  size_t strpos = prePend.find(".dec");
508  prePend = prePend.substr(0, strpos);
509  prePend.append("_");
510 
511  std::ostringstream ss;
512  exposureCount++;
513  ss << setw(4) << setfill('0') << exposureCount;
514  prePend.append(ss.str().c_str());
515  prePend.append("_");
516 
517  prePend.append(to_string(exposureID));
518  prePend.append("_");
519 
520  string outName;
521  outName.assign(prePend);
522  outName.append(packetOutname);
523 
524  rename( tempName.c_str(), outName.c_str());
525 
526  outName.append(".txt");
527 
528  textOut.open(outName.c_str(), ios::out | ios::trunc);
529  textOut << "TlmFile=" << basename( argv[1]) << endl;
530  textOut << "StartTime=" << zuluStartTime.c_str() << endl;
531  textOut << "StopTime =" << zuluStopTime.c_str() << endl;
532  textOut << "ExposureID=" << to_string(exposureID).c_str() << endl;
533  textOut << "StartHWKTime=" << to_string(startHWKTime).c_str() << endl;
534  textOut << "StopHWKTime =" << to_string(stopHWKTime).c_str() << endl;
535  textOut.close();
536  } // for (int i=0; i<tempCnt; i++)
537 
538  framefile.close();
539  gpsOut.close();
540 
541  return 0;
542 }
543 
544 
545 int getZuluTime_L0Name( double tlm_time,
546  string *zuluTime, string *packetOutName) {
547 
548  int32_t iyr, idy;
549  int16_t mon, idm, hr, min;
550  double sec;
551 
552  tepoch2yds( tlm_time, &iyr, &idy, &sec);
553  yd2md((int16_t) iyr, (int16_t) idy, &mon, &idm);
554 
555  // cout << iyr << " " << idy << " " << sec << endl;
556 
557  stringstream ss;
558 
559  // yyyy-mn-dyThr:mn:ss.sss
560  ss = stringstream();
561  ss << setw(4) << to_string(iyr) << "-";
562  ss << setw(2) << setfill('0') << mon << "-";
563  ss << setw(2) << setfill('0') << idm << "T";
564  hr = (int) sec/3600;
565  min = (int) ((sec - hr*3600) / 60);
566  sec = sec - hr*3600 - min*60;
567  ss << setw(2) << setfill('0') << hr << ":";
568  ss << setw(2) << setfill('0') << min << ":";
569  ss << fixed << setw(6) << setprecision(3) << setfill('0') << sec;
570 
571  zuluTime->assign( ss.str());
572 
573  // HWKyyyydoyhrmnsc.L0_SE1
574  if (packetOutName != NULL) {
575  ss = stringstream();
576  ss << "HWK" << setw(4) << to_string(iyr);
577  ss << setw(3) << setfill('0') << to_string(idy);
578  ss << setw(2) << setfill('0') << hr;
579  ss << setw(2) << setfill('0') << min;
580  ss << setw(2) << setfill('0') << (int) sec;
581  ss << ".L0_SE1";
582  packetOutName->assign( ss.str());
583  }
584 
585  return 0;
586 }
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
#define VERSION
#define NULL
Definition: decode_rs.h:63
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
float32 * pos
Definition: l1_czcs_hdf.c:35
def remove(file_to_delete)
Definition: ProcUtils.py:319
#define DATAFRAMEBYTES
int tepoch2yds(double tepoch, int32_t *iyr, int32_t *idy, double *sec)
void yd2md(int16_t year, int16_t doy, int16_t *month, int16_t *dom)
Definition: yd2md.c:6
int main(int argc, char *argv[])
int getZuluTime_L0Name(double tlm_time, string *zuluTime, string *packetOutName)
integer, parameter double
#define SWAP_2(x)
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude data
Definition: HISTORY.txt:356
#define basename(s)
Definition: l0chunk_modis.c:29
double trunc(double)
int getSHpacket(ifstream *framefile, uint8_t frame[892], int &framePtr, uint8_t **packet, int &packetLength, int &prevFrameCnt, int &frameDrop, bool isVerbose)
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 per delivery and then split off a new MYD_PR03 pcf file for Aqua Added AssociatedPlatformInstrumentSensor to the inventory metadata in MOD01 mcf and MOD03 mcf Created new versions named MYD01 mcf and MYD03 where AssociatedPlatformShortName is rather than Terra The program itself has been changed to read the Satellite Instrument validate it against the input L1A and LUT and to use it determine the correct files to retrieve the ephemeris and attitude data from Changed to produce a LocalGranuleID starting with MYD03 if run on Aqua data Added the Scan Type file attribute to the Geolocation copied from the L1A and attitude_angels to radians rather than degrees The accumulation of Cumulated gflags was moved from GEO_validate_earth_location c to GEO_locate_one_scan c
Definition: HISTORY.txt:464
int32_t idy
Definition: atrem_corl1.h:161
int i
Definition: decode_rs.h:71
int32_t iyr
Definition: atrem_corl1.h:161