NASA Logo
Ocean Color Science Software

ocssw V2022
l0info_oci.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 
3 
4 __version__ = '2.8.0_2023-08-09'
5 
6 __dtypes__ = ['','','_DARK','_SOL','_SPCA','_LIN','_LUN','_DIAG','_STAT',
7  '_SPEC','','_SNAP-X','_SNAP-I','','_LUN-ST','_RAW']
8 
9 import numpy as np
10 from l0info_utils import read_packet, read_apid, get_anc_packet_time, is_bad_packet
11 
12 
13 
14 CRC_TABLE = [0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5,
15  0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b,
16  0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210,
17  0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
18  0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c,
19  0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401,
20  0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b,
21  0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
22  0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6,
23  0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738,
24  0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5,
25  0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
26  0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969,
27  0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96,
28  0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc,
29  0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
30  0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03,
31  0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd,
32  0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6,
33  0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
34  0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a,
35  0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb,
36  0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1,
37  0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
38  0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c,
39  0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2,
40  0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb,
41  0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
42  0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447,
43  0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8,
44  0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2,
45  0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
46  0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9,
47  0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827,
48  0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c,
49  0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
50  0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0,
51  0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d,
52  0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07,
53  0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
54  0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba,
55  0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74,
56  0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
57  ]
58 CRC_LENGTH: int = 4
59 
60 science_oci_format_header = 0x2bc
61 shift_bit = 0xffff
62 
63 
64 def compute_CRC_checksum(data: list, length: int):
65  # byte_0 = 0x34 - Logical Address
66  # byte_1 = 0x02 - protocol ID
67  CRC_BUFFER: list[int] = [ 0x34,0x02] # placing these two bytes in the beggining (SpaceWire Header)
68  crcA = 0xFFFF
69  crcB = 0xFFFF
70  CRC_BUFFER += data[:length]
71  size = (length + 2) // 4
72  for i in range(size):
73  crcA = CRC_TABLE[((crcA >> 8) ^ CRC_BUFFER[4 * i + 0])
74  & 0xFF] ^ (crcA << 8)
75  crcA = crcA & shift_bit
76  crcA = CRC_TABLE[((crcA >> 8) ^ CRC_BUFFER[4 * i + 1])
77  & 0xFF] ^ (crcA << 8)
78  crcA = crcA & shift_bit
79  crcB = CRC_TABLE[((crcB >> 8) ^ CRC_BUFFER[4 * i + 2])
80  & 0xFF] ^ (crcB << 8)
81  crcB = crcB & shift_bit
82  crcB = CRC_TABLE[((crcB >> 8) ^ CRC_BUFFER[4 * i + 3])
83  & 0xFF] ^ (crcB << 8)
84  crcB = crcB & shift_bit
85  return (crcA << 16) | crcB
86 
87 
88 
89 def get_band_dims(apacket):
90 
91 # extract aggregation information and compute data dimensions from ancillary packet
92 
93 # Arguments
94 #
95 # Name Type I/O Description
96 # ---- ---- --- -----------
97 # apacket byte(*) I Ancillary packet array
98 # ncp int O Number of CCD band pixels
99 # nbb int O Number of blue CCD bands
100 # nrb int O Number of red CCD bands
101 # nsp int O Number of SWIR band pixels
102 # ndc int O Number of CCD dark collect pixels
103 # nds int O Number of SWIR dark collect pixels
104 # btaps int O Blue CCD tap enable flags
105 # rtaps int O Red CCD tap enable flags
106 # itable struct O Spatial aggregation table
107 
108 # orig: Frederick S. Patt, SAIC, 1 August 2018
109 
110  # Create spatial aggregation table structure
111  itable = np.zeros(10, dtype={'names':('dtype', 'iagg', 'lines'),'formats':('i4','i4','i4')})
112 
113  # Extract spatial aggregation table and compute numbers of pixels
114  ioff = 36
115  nagg = [1,2,4,8]
116  ncp = 0
117  nsp = 0
118  ndc = 0
119  nds = 0
120  for i in range(0,10):
121  itable['dtype'][i] = apacket[ioff+3]%16
122  itable['iagg'][i] = apacket[ioff+2]%4
123  itable['lines'][i] = apacket[ioff]*256 + apacket[ioff+1]
124  ioff = ioff + 4
125  if ((itable['dtype'][i] > 0) and (itable['dtype'][i] <= 12) and (itable['dtype'][i] != 10)):
126  if (itable['dtype'][i] == 2):
127  ndc = ndc + itable['lines'][i]/nagg[itable['iagg'][i]]
128  nds = nds + itable['lines'][i]/8
129  ncp = ncp + itable['lines'][i]/nagg[itable['iagg'][i]]
130  nsp = nsp + itable['lines'][i]/8
131  if (ncp == 0):
132  ncp = 1
133  nsp = 1
134 
135  if (ndc == 0):
136  ndc = 1
137  nds = 1
138 
139  ioff = ioff + 4
140 
141  # Extract spectral aggregation and compute numbers of bands
142  # Tap enable flags
143  btap = apacket[ioff+2]*256 + apacket[ioff+3]
144  rtap = apacket[ioff]*256 + apacket[ioff+1]
145  btaps = np.zeros(16)
146  rtaps = np.zeros(16)
147 
148  # Tap aggregation factors
149  bagg = int.from_bytes(apacket[ioff+8:ioff+12],'big')
150  ragg = int.from_bytes(apacket[ioff+4:ioff+8],'big')
151 
152  baggs = np.zeros(16)
153  raggs = np.zeros(16)
154 
155  # Compute number of bands for enabled taps
156  nbb = 0
157  nrb = 0
158  ken = 1
159  kag = 3
160  lag = 1
161 
162  for i in range(15,-1,-1):
163  btaps[i] = np.bitwise_and(btap, ken)/ken
164  if (btaps[i]):
165  baggs[i] = nagg[int(np.bitwise_and(bagg, kag)/lag)]
166  nbb = nbb + 32/baggs[i]
167 
168  rtaps[i] = np.bitwise_and(rtap, ken)/ken
169  if (rtaps[i]):
170  raggs[i] = nagg[int(np.bitwise_and(ragg, kag)/lag)]
171  nrb = nrb + 32/raggs[i]
172 
173  ken = ken*2
174  kag = kag*4
175  lag = lag*4
176 
177  return ncp,nbb,nrb,nsp,ndc,nds,btaps,rtaps,itable,baggs,raggs
178 
179 def anc_compare(apacket0,apacket):
180 
181 # function to compare spatial and spectral data collection parameters
182 # from two OCI ancillary data packets
183 
184 # Arguments
185 #
186 # Name Type I/O Description
187 # ---- ---- --- -----------
188 # apacket0(*) byte I Ancillary packet from first spin
189 # apacket(*) byte I Ancillary packet from next spin
190 
191 # Returns 1 (TRUE) if packets agree, 0 if not
192 
193  anc_compare = 1
194  strmsg = ""
195  # Compare spatial data collection fields
196  ioff = 36
197  ilen = 40
198  if apacket[ioff:ioff+ilen] != apacket0[ioff:ioff+ilen]:
199  c_time = get_anc_packet_time(apacket)
200  strmsg += "\nSpatial table change at %s" % c_time.strftime('%Y-%m-%dT%H:%M:%S.%f')
201  anc_compare = 0
202 
203  # Compare spectral data collection fields
204  joff = 80
205  jlen = 12
206  if apacket[joff:joff+jlen] != apacket0[joff:joff+jlen]:
207  c_time = get_anc_packet_time(apacket)
208  strmsg += "\nSpectral table change at %s" % c_time.strftime('%Y-%m-%dT%H:%M:%S.%f')
209  anc_compare = 0
210 
211  return anc_compare, strmsg
212 
213 def is_bad_apid(apid,fh):
214  if apid == -1:
215  return False
216  if (apid < 550) or (apid > 749):
217  print("Invalid packet header at byte %d."%fh.tell())
218  return True
219  else:
220  return False
221 
222 def get_oci_data_type(fpacket):
223  # To determine the OCI data type from and ancillary packet
224  # Returns: dtype (1 - 12) if valid ancillary packet, -1 otherwise
225 
226  # Check APID
227  apid = read_apid(fpacket)
228  if (apid != 636): return -1
229 
230  dtypes = np.zeros(10)-1
231  ioff = 36
232  for i in range(0,10):
233  dtypes[i] = fpacket[ioff+3] % 16
234  ioff = ioff + 4
235  kd = np.argwhere((dtypes != 2) & (dtypes != 10)) # Exclude dark and no processing types
236  dtype = np.max(dtypes[kd])
237 
238  return int(dtype)
239 
240 
241 def l0info_oci(args, fh, output, bDSB, crcSumCheck):
242  # procedure to get start and end times from Level-0 packet files for OCI
243  print("Running l0info_oci (version: %s) \n" % __version__)
244 
245  dtype = -1
246  str_stime = ''
247  str_etime = ''
248 
249  status = 0
250  if args.verbose:
251  print("Reading OCI science data file.")
252 
253  bSPW = False
254  lpoint = 0
255  if bDSB:
256  # chead = fh.read(64)
257  lpoint = 64
258  bSPW = True
259  fh.seek(lpoint)
260 
261  # Get first ancillary packet
262  apid = 0
263  packetLength = 8
264  if crcSumCheck:
265  print("CRC checksum will be perfomed for each science packet")
266  while (apid != 636) and (packetLength > 7):
267  try:
268  fpacket, packetLength = read_packet(fh, bSPW)
269  apid = read_apid(fpacket)
270  if is_bad_apid(apid,fh): return 104
271 
272  # check CRC sum
273  if fpacket and crcSumCheck:
274  phead_format = int.from_bytes(fpacket[:2], "big")
275  if phead_format == science_oci_format_header:
276  dataCompute = list(fpacket[0:-CRC_LENGTH])
277  crcCalcs = compute_CRC_checksum(dataCompute, len(dataCompute))
278  crcExpected = int.from_bytes(fpacket[-CRC_LENGTH:], "big")
279  if crcExpected != crcCalcs:
280  print(f"Error : CRC checksum failed! Expected {hex(crcExpected)}, calculated {hex(crcCalcs)} for packet with apid {apid}")
281  return 131
282  except:
283  return 103
284  if is_bad_packet(packetLength,fh): return 104
285  if fpacket:
286  print("CRC check finished.")
287 
288  # If no ancillary packets, rewind and get times from HKT packets
289  if fpacket is None:
290  print('No stored science packets found in file.')
291  status = 110
292 
293  fh.seek(lpoint)
294  apid = 0
295  packetLength = 8
296  ccsec = 0
297  firstraw = 0
298  # while ((apid < 550) or (apid > 750) or (apid == 558)) and (packetLength > 8):
299  while (ccsec < 1900000000) and (packetLength>7):
300  fpacket, packetLength = read_packet(fh, bSPW)
301  if fpacket:
302  apid = read_apid(fpacket)
303  else:
304  continue
305  ccsec = int.from_bytes(fpacket[6:10],'big')
306  # if is_bad_packet(packetLength,fh): return 104
307  if fpacket:
308  mpacket = fpacket
309  try:
310  stime = get_anc_packet_time(mpacket[6:12],0,'msec')
311  str_stime = stime.strftime('%Y-%m-%dT%H:%M:%S.%f')
312  # print("start_time=%s" % str_stime)
313  except:
314  return 120
315 
316  while fpacket and (packetLength>7):
317  fpacket, packetLength = read_packet(fh, bSPW)
318  if fpacket:
319  apid = read_apid(fpacket)
320  else:
321  continue
322 
323  # Check for raw mode
324  if (apid == 705) and (not firstraw):
325  dtype = 15 # '_RAW'
326  firstraw = 1
327 
328  if (apid >= 550) and (apid < 750) and (apid!=705): mpacket = fpacket
329 
330  if is_bad_packet(packetLength,fh): return 104
331  print("start_time=%s" % str_stime)
332  etime = get_anc_packet_time(mpacket[6:12],0,'msec')
333  else:
334  if output:
335  output.write("datatype=OCI\n")
336  print("No packets with valid time tags in file.")
337  return status
338 
339  else:
340  # Get data type
341  dtype = get_oci_data_type(fpacket)
342  if (dtype<1) or (dtype>12):
343  print("Invalid data type %d."%dtype)
344  return 104
345 
346  # Get start time
347  try:
348  stime = get_anc_packet_time(fpacket,28,'usec')
349  str_stime = stime.strftime('%Y-%m-%dT%H:%M:%S.%f')
350  print("start_time=%s" % str_stime)
351  epacket = fpacket
352  etime = get_anc_packet_time(epacket,28,'usec')
353  except:
354  return 120
355 
356  # Read to end of file
357  apacket = fpacket
358  acomp = 0
359  nagg = np.array([1,2,4,8])
360  spnp = int.from_bytes(apacket[24:28],'big')
361 
362  while fpacket:
363  etime = get_anc_packet_time(apacket,28,'usec')
364  if args.verbose:
365  # spnum = swap_endian(long(apacket(24:27),0))
366  spnum = int.from_bytes(apacket[24:28],'big')
367  tmpstr = ""
368  if ((spnum-spnp) > 10):
369  tmpstr += "\nSpin number gap: %d, %d" % (spnp, spnum)
370  spnp = spnum
371  if (not acomp):
372  tmpstr += "\n\nInstrument configuration change at spin %d, %s" % (spnum,etime)
373  ncp,nbb,nrb,nsp,ndc,nds,btaps,rtaps,itable,baggs,raggs = get_band_dims(apacket)
374  iz = np.where((itable['dtype'] != 0) & (itable['dtype'] != 10))[0]
375  tmpstr += "\nData Type %s" % str(itable['dtype'][iz])
376  iagg = nagg[itable['iagg'][iz]]
377  tmpstr += "\nNumber of pixels %s" % str(itable['lines'][iz]/iagg)
378  tmpstr += "\nAggregation %s" % str(iagg)
379  tmpstr += "\nBlue bands: %d Red bands: %d" %(nbb, nrb)
380  tmpstr += "\nBlue aggregation per tap: %s" % str(baggs)
381  tmpstr += "\nRed aggregation per tap: %s\n" % str(raggs)
382  print(tmpstr)
383 
384  apacket = fpacket
385 
386  apid = 0
387  while (apid != 636) and (packetLength>0):
388  fpacket, packetLength = read_packet(fh, bSPW)
389  apid = read_apid(fpacket)
390  if is_bad_apid(apid,fh): return 104
391 
392  if is_bad_packet(packetLength,fh): return 104
393  if fpacket: epacket = fpacket
394 
395  try:
396  etime = get_anc_packet_time(epacket,28,'usec')
397  except:
398  return 120
399 
400  str_etime = etime.strftime('%Y-%m-%dT%H:%M:%S.%f')
401  print("stop_time=%s" % str_etime)
402 
403  datatype_name = ''
404  if dtype > 0:
405  try:
406  datatype_name = 'OCI' + __dtypes__[dtype]
407  if datatype_name=="OCI_LUN-ST":
408  print("Unexpected datatype [%s] is detected." % datatype_name)
409  status = 130
410  except:
411  print("OCI data type name reading error.")
412  status = 130
413 
414  if datatype_name=='':
415  datatype_name = 'OCI'
416 
417  print("datatype=%s" % datatype_name)
418  if output:
419  output.write("datatype=%s\n" % datatype_name)
420  if str_stime!='':
421  output.write("start_time=%s\n" % str_stime)
422  if str_etime!='':
423  output.write("stop_time=%s\n" % str_etime)
424 
425  return status
def get_band_dims(apacket)
Definition: l0info_oci.py:89
def anc_compare(apacket0, apacket)
Definition: l0info_oci.py:179
def read_apid(fpacket)
Definition: l0info_utils.py:93
def l0info_oci(args, fh, output, bDSB, crcSumCheck)
Definition: l0info_oci.py:241
list(APPEND LIBS ${NETCDF_LIBRARIES}) find_package(GSL REQUIRED) include_directories($
Definition: CMakeLists.txt:8
def is_bad_apid(apid, fh)
Definition: l0info_oci.py:213
def get_oci_data_type(fpacket)
Definition: l0info_oci.py:222
void print(std::ostream &stream, const char *format)
Definition: PrintDebug.hpp:38
int get_anc_packet_time(uint8_t *apacket, int32_t &iyear, int32_t &iday, double &stime)
Definition: common.cpp:104
int read_packet(FILE *infile, uint8_t packet[], int *len, long int *endfile)
Definition: read_packet.c:18
def compute_CRC_checksum(list data, int length)
Definition: l0info_oci.py:64
def is_bad_packet(packetLength, fh)
Definition: aerosol.c:136