Skip to content
Snippets Groups Projects
Commit 58a71e9a authored by Bruce Flynn's avatar Bruce Flynn
Browse files

Remove dependence on edos pkg

parent 8323413e
No related branches found
No related tags found
No related merge requests found
# -*- coding: utf-8 -*-
"""
CCSDS BaseStruct implementations for AQUA.
Structures for CCSDS Primary and Secondary headers
See:
ICD_Space_Ground_Aqua.pdf
GSFC 422-11-19-03
Last known location:
http://directreadout.sci.gsfc.nasa.gov/links/rsd_eosdb/PDF/ICD_Space_Ground_Aqua.pdf
* ICD_Space_Ground_Aqua.pdf - GSFC 422-11-19-03
- http://directreadout.sci.gsfc.nasa.gov/links/rsd_eosdb/PDF/ICD_Space_Ground_Aqua.pdf
* CCSDS Space Packet Protocol
- http://public.ccsds.org/publications/archive/133x0b1c2.pdf
* CCSDS Time Code Formats
- http://public.ccsds.org/publications/archive/301x0b4e1.pdf
"""
import ctypes as c
from datetime import datetime, timedelta
from edos.ccsds import (
GROUP_FIRST,
GROUP_LAST,
GROUP_CONTINUING,
GROUP_STANDALONE
)
from edosl0util.timecode import cds_stamp, cds_to_timestamp
GROUP_FIRST = 0b01
GROUP_LAST = 0b10
GROUP_CONTINUING = 0b00
GROUP_STANDALONE = 0b11
class BaseStruct(c.BigEndianStructure):
_pack_ = 1
......@@ -35,8 +36,25 @@ class BaseStruct(c.BigEndianStructure):
return '<%s (%s)>' % (self.__class__.__name__, fields)
class Timecode(BaseStruct):
class PrimaryHeader(BaseStruct):
"""
CCSDS Primary Header.
"""
_fields_ = [
('version_number', c.c_uint8, 3), # == 0
('type_indicator', c.c_uint8, 1),
('secondary_header_flag', c.c_uint8, 1),
('apid', c.c_uint16, 11),
('sequence_grouping', c.c_uint16, 2),
('source_sequence_count', c.c_uint16, 14),
('data_length_minus1', c.c_uint16) # octet count minus one
]
class Timecode(BaseStruct):
"""
Secondary header timecode baseclass.
"""
def astimestamp(self):
raise NotImplementedError()
......@@ -48,13 +66,18 @@ class AquaCucTimecode(Timecode):
"""
EOS AQUA implementation of a CCSDS Unsegmented Timecode. An CUT is an
agency defined timecode which is in this case (I think) specific to Aqua.
NOTE: I'm betting this will work for Terra as well but I do not have any
documentation for Terra.
FIXME: Not tested or validated!!
"""
_fields_ = [
('extension_flag', c.c_uint8, 1), # 1
('timecode_epoch', c.c_uint8, 3), # 010 == Jan 1, 1958
('coarse_time_count', c.c_uint8, 2), # 11 == 4 octets
('fine_time_count', c.c_uint8, 2), # 10 == 2 octets
('no_continuation_flag', c.c_uint8, 1), # 0
('extension_flag', c.c_uint8, 1),
('timecode_epoch', c.c_uint8, 3),
('coarse_time_count', c.c_uint8, 2),
('fine_time_count', c.c_uint8, 2),
('no_continuation_flag', c.c_uint8, 1),
('leap_seconds', c.c_uint8, 7),
('seconds', c.c_uint32),
('sub_seconds', c.c_uint16)
......@@ -81,6 +104,9 @@ class AquaCucTimecode(Timecode):
class DaySegmentedTimecode(Timecode):
"""
CCSDS Day Segmented Timecode
"""
_pack_ = 1
_fields_ = [
('days', c.c_uint16),
......@@ -98,16 +124,14 @@ class DaySegmentedTimecode(Timecode):
return cds_stamp(self.days, self.milliseconds, self.microseconds)
class GirdSecondaryHeader(BaseStruct):
_pack_ = 1
class AquaGirdSecondaryHeader(BaseStruct):
_fields_ = [
('flags', c.c_uint8),
('timecode', AquaCucTimecode),
]
class GiisSecondaryHeader(BaseStruct):
_pack_ = 1
class AquaGiisSecondaryHeader(BaseStruct):
_fields_ = [
('timecode', DaySegmentedTimecode),
('quicklook_flag', c.c_uint8, 1),
......@@ -115,12 +139,42 @@ class GiisSecondaryHeader(BaseStruct):
]
class SpacecraftBusSecondaryHeader(BaseStruct):
class AquaSpacecraftBusSecondaryHeader(BaseStruct):
_fields_ = [
('timecode', AquaCucTimecode)
]
class JpssSecondaryHeader(BaseStruct):
"""
Secondary header using Day Segmented timecodes.
"""
_pack_ = 1
_fields_ = [
('timecode', DaySegmentedTimecode)
]
class JpssFirstSecondaryHeader(BaseStruct):
"""
Secondary header using Day Segmented timecodes and with a packet count.
"""
_pack_ = 1
_fields_ = [
('timecode', DaySegmentedTimecode),
('packet_count', c.c_uint8),
('_spare', c.c_uint8)
]
def jpss_header_lookup(primary_header):
grouping = primary_header.sequence_grouping
if grouping == GROUP_FIRST:
return JpssFirstSecondaryHeader
elif grouping == GROUP_STANDALONE:
return JpssSecondaryHeader
def amsu_headers():
apids = [
# AMSU-A1
......@@ -129,7 +183,7 @@ def amsu_headers():
288, 289, 290
]
flags = [GROUP_FIRST, GROUP_CONTINUING, GROUP_LAST, GROUP_STANDALONE]
return {(apid, flag): GirdSecondaryHeader
return {(apid, flag): AquaGirdSecondaryHeader
for apid in apids
for flag in flags}
......@@ -137,32 +191,32 @@ def amsu_headers():
def airs_headers():
return {
# AIRS
(404, GROUP_STANDALONE): GirdSecondaryHeader,
(405, GROUP_STANDALONE): GirdSecondaryHeader,
(406, GROUP_STANDALONE): GirdSecondaryHeader,
(407, GROUP_STANDALONE): GirdSecondaryHeader,
(414, GROUP_STANDALONE): GirdSecondaryHeader,
(415, GROUP_STANDALONE): GirdSecondaryHeader,
(416, GROUP_STANDALONE): GirdSecondaryHeader,
(417, GROUP_STANDALONE): GirdSecondaryHeader,
(404, GROUP_STANDALONE): AquaGirdSecondaryHeader,
(405, GROUP_STANDALONE): AquaGirdSecondaryHeader,
(406, GROUP_STANDALONE): AquaGirdSecondaryHeader,
(407, GROUP_STANDALONE): AquaGirdSecondaryHeader,
(414, GROUP_STANDALONE): AquaGirdSecondaryHeader,
(415, GROUP_STANDALONE): AquaGirdSecondaryHeader,
(416, GROUP_STANDALONE): AquaGirdSecondaryHeader,
(417, GROUP_STANDALONE): AquaGirdSecondaryHeader,
}
def hsb_headers():
return {
# HSB
(342, GROUP_STANDALONE): GirdSecondaryHeader,
(342, GROUP_STANDALONE): AquaGirdSecondaryHeader,
}
def modis_headers():
return {
# MODIS
(64, GROUP_STANDALONE): GiisSecondaryHeader,
(64, GROUP_FIRST): GiisSecondaryHeader,
(64, GROUP_LAST): GiisSecondaryHeader,
(64, GROUP_CONTINUING): GiisSecondaryHeader,
(127, GROUP_STANDALONE): GiisSecondaryHeader,
(64, GROUP_STANDALONE): AquaGiisSecondaryHeader,
(64, GROUP_FIRST): AquaGiisSecondaryHeader,
(64, GROUP_LAST): AquaGiisSecondaryHeader,
(64, GROUP_CONTINUING): AquaGiisSecondaryHeader,
(127, GROUP_STANDALONE): AquaGiisSecondaryHeader,
}
......@@ -174,13 +228,13 @@ def ceres_headers():
157, 158, 159, 160
)
groupings = (GROUP_FIRST, GROUP_CONTINUING, GROUP_LAST, GROUP_STANDALONE)
return {(a, g): GiisSecondaryHeader for a in apids for g in groupings}
return {(a, g): AquaGiisSecondaryHeader for a in apids for g in groupings}
def gbad_headers():
return {
# GBAD
(957, GROUP_STANDALONE): SpacecraftBusSecondaryHeader
(957, GROUP_STANDALONE): AquaSpacecraftBusSecondaryHeader
}
......@@ -198,38 +252,7 @@ def aqua_headers():
return headers
class JpssSecondaryHeader(BaseStruct):
"""Secondary Header for a JSPP CCSDS packet that is not part of a packet
sequence.
"""
_pack_ = 1
_fields_ = [
('timecode', DaySegmentedTimecode)
]
class JpssFirstSecondaryHeader(BaseStruct):
"""Secondary Header for a JSPP CCSDS packet that is the first packet in a
packet sequence. Following packets that are part of this sequence will not
have a secondary header.
"""
_pack_ = 1
_fields_ = [
('timecode', DaySegmentedTimecode),
('packet_count', c.c_uint8),
('_spare', c.c_uint8)
]
def jpss_header_lookup(primary_header):
grouping = primary_header.sequence_grouping
if grouping == GROUP_FIRST:
return JpssFirstSecondaryHeader
elif grouping == GROUP_STANDALONE:
return JpssSecondaryHeader
def aqua_header_lookup(primary_header): # noqa
def aqua_header_lookup(primary_header):
apid = primary_header.apid
grouping = primary_header.sequence_grouping
return _aqua_headers.get((apid, grouping))
......
import io
import logging
import ctypes as c
from collections import deque, defaultdict
from edos.ccsds import (
c,
from edosl0util.headers import (
PrimaryHeader,
GROUP_FIRST,
GROUP_CONTINUING,
GROUP_LAST,
GROUP_STANDALONE
)
from edosl0util import headers
......@@ -19,17 +23,15 @@ def simple_stream(fobj):
"""
Generator that yields PrimaryHeaders and data. Files are read using mmap.
"""
if fobj is not None:
data = fobj
psize = c.sizeof(PrimaryHeader)
while True:
buf = data.read(psize)
buf = fobj.read(psize)
if len(buf) < psize:
return
h1 = PrimaryHeader.from_buffer_copy(buf)
# read user data
size = h1.data_length_minus1 + 1
buf = data.read(size)
buf = fobj.read(size)
if len(buf) < size:
return
yield h1, buf
......@@ -102,16 +104,16 @@ class Packet(object):
return False
def is_first(self):
return self.primary_header.sequence_grouping == 0b01
return self.primary_header.sequence_grouping == GROUP_FIRST
def is_continuine(self):
return self.primary_header.sequence_grouping == 0b00
return self.primary_header.sequence_grouping == GROUP_CONTINUING
def is_last(self):
return self.primary_header.sequence_grouping == 0b10
return self.primary_header.sequence_grouping == GROUP_LAST
def is_standalone(self):
return self.primary_header.sequence_grouping == 0b11
return self.primary_header.sequence_grouping == GROUP_STANDALONE
class PacketStream(object):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment