LDCM CFDP File Extraction - The CCSDS Collaborative Work

advertisement
Consultative Committee on Space Data Systems
Next Gen Uplink Working Group
Landsat Data Continuity Mission (LDCM) CCSDS File Extraction
Protocol (CFDP) ‐ A Working Guideline In Pseudo Code
NGU_11‐xx
H. Garon1, V.Sank1, K.Dearth
NASA Goddard Space Flight Center, Greenbelt, MD 20771
1
MEI
CCSDS Next Gen Uplink WG meeting
16 May 2011
Introduction and Background
The CCSDS File delivery Protocol (CFDP) format as specified within the Landsat Data
Continuity Mission (LDCM) Space‐To‐Ground Interface Control Document (ICD) [1] is
both precise and comprehensive. Like most specifications, though, a leap in logic is still
required when it comes to actually building something that works in practice. Further
exacerbating a complicated housekeeping problem, LDCM can transmit a mission data
stream containing up to four CFDP files interleaved simultaneously. Simple extraction
routines that may succeed in handling a single file at a time will usually fail under those
circumstances. Our intent here is remove any ambiguity with respect to building a CFDP
file extraction routine and touch upon the subtler details in implementation, particularly
as it pertains to LDCM.
Discussion
LDCM’s implementation of CFDP does follow the CCSDS Blue Book recommendations
within CCSDS 727.0‐B‐3 [2]. LDCM does follow CCSDS in general with the two
exceptions – (1) reversing the attached synchronization markers (ASM) distinguishing
code frame from transfer frame and (2), having a code frame asynchronous to the
transfer frame. The rationale for these particular design decisions and more for LDCM
were based upon an operational supposition. In order to fulfill its basic scientific mission
given a limited contact time between satellite and ground station, LDCM required an
effective bit‐error‐rate (BER) of less than 10‐12 over a 440 Msps downlink. The veracity of
that supposition has since been demonstrated[3] and was realizable, in part, because
LDCM also relied upon a 7/8‐rate Low‐density Parity Check (LDPC) codec with fixed‐size
blocks. Referring to figure 1, the LDPC frame markers delineating every code block are
clearly shown asynchronous with respect to the frame markers corresponding to each
transfer frame or Channel Access Data Unit (CADU). Although not discussed explicitly in
[2], the CADUs correspond to the basic building blocks of every CFDP file within LDCM.
In LDCM’s specific implementation of the CFDP, the Transaction ID within each CADU’s
Transfer Frame Primary Header is always zero. As a substitute to using the Transaction
ID, the Virtual Channel ID (VCID) is used instead. Interleaving the CADUs for up to four
CFDP files simultaneously requires that the VCID be unique and consistent in order to
uniquely and distinctly identify each file from the others. The only way a VCID can be
reused in starting a new CFDP file is by first closing any previous file having the same
VCID.
Figure 1. LDCM Asynchronous Data Transfer Frame and Code Frame
We recognize that providing pseudo‐code can still leave a gap between definition and
implementation. For that reason we chose to build the pseudo‐code within a
Mathworks Matlabtm development environment. The Matlab environment is well‐
defined and the Mathworks support is extraordinary, both online and in the local help.
The result is a “working” pseudo‐code (LDCMCFDPreader.m) in the sense that it can be
used to construct a fully functional executable. In fact, the code listing at the end of this
document was debugged using over 60 Gbytes of post‐decoder mission data covering a
very wide range of transmission possibilities. Its purpose, nonetheless, remains to serve
as pseudo‐code and as a vehicle to assist the user in porting to a preferential
environment and platform.
A few words are relevant concerning the robustness of the code. The code is not a fully
general implementation because it does not allow for the possibility of bit errors in the
data stream. Converting the code to handle most anticipated errors should be
straightforward. As an example, the detection of the Attached Sync Marker (ASM)
defining the beginning of each CADU could be easily generalized by allowing a bit “vote”
for identification of the best ASM position, using a combination of preceding CADU and
post‐CADU ASM position and ASM bit‐matching correlation. This process is very similar
to the methods used to maintain decoder lock.
Structure of the Code
The key to building a successful CFDP extraction routine lies in recognizing the
boundaries of each CADU. The boundaries of a CADU are sacrosanct and, once defined,
are invariant. Following the flow diagram of figure 2, once the ASM of a CADU is
detected processing of the CADU begins. For LDCM the CADU has a fixed required
length of 1034 bytes. As discussed above, our code makes no allowances for bit errors
so the end boundary of the CADU is expected after accumulating 1034 bytes after the
start of the ASM. All decoding of the CADU follows a Big Endian format with sequential
byte order establishing byte significance, e.g., a 16 bit word is composed of two bytes,
the first byte in order being the most significant byte and the second byte least
significant. Bit significance within a byte follows the same precedence with the highest
order bit having the greatest weight. Each CADU contains at a minimum the ASM (4
bytes) and a Transfer Frame Header (6 bytes) followed by an M_PDU Header (2 bytes).
The remaining 1022 bytes may contain a combination of headers and mission data or
just mission data. In stark contrast to the ASM, Transfer Frame Header and M_PDU
Header, the remaining subheaders and/or data do not have to fit neatly into a single
CADU. These subheaders and data also follow one of two fixed sequences whose
constituents are dictated by the subheaders themselves, viz.,
Sequence 1: Space Packet Primary Header, CFDP Header, File Directive Header
with either Metadata PDU or End‐Of‐File PDU, or
Sequence 2: Space Packet Primary Header, CFDP Header, Offset Header and
Mission Data Header, followed by data with length defined in Mission Data
Header.
Any of these subheaders may split across a pair of CADU boundaries. On the other hand,
data can split across multiple CADU boundaries. Many parameters within the
subheaders are linked (or related) to the value of parameters in other subheaders. This
offers the opportunity to do cross‐checking if desired as well as reconstruction should a
bit error occur in reception.
By using a switch operator based upon an assigned task, the code can handle each of
the subheaders independently. The primary problem is to retain housekeeping of key
parameters that are required to transit between one CADU to another CADU. Since
*That opens additional possibilities for error recovery, regardless of whether that error occurs either in
omission or value. The structure of CFDP has sufficient rigidity and internal redundancy that it could allow
us to “fill” in the case of omission and “reconstruct” in the case of value, especially with regard to single
isolated bit errors. The CCSDS recommendation, though, is to dispose of the file in the event of an
unrecoverable (hard) error and issue a negative acknowledgment (NAK).
LDCM can transmit up to four CFDP files simultaneously, the next CADU in a CADU
sequence appropriate to a given Virtual Channel does not have to follow immediately in
order. In fact, Virtual Channels (and their corresponding CADUs) may appear and
disappear at any time prior to completing file extraction. The code anticipates this by
putting all the key housekeeping parameters for a given Virtual Channel into a single
structure specifically for that Virtual Channel. This permits each Virtual Channel to be
totally self‐contained and self‐tracking. The code restricts the number of simultaneous
CFDP file extractions to four but this may be easily changed to any number.
Termination of the CFDP file extraction sequence for a given Virtual Channel requires at
a minimum the reception of an End‐Of‐File (EOF) PDU. How much fill data is allowed
pass the EOF PDU is driven by the LDCM maximum file size (1 Gbyte = 1024*1024*1024
bytes). Less than 1 Gbyte the file is terminated at the CADU containing the EOF PDU.
The only other case corresponds to a file terminated precisely at end of the CADU
corresponding to the 1 Gbyte boundary.
Summary
The LDCM implementation of the CFDP is intentionally designed to be both simple and
straightforward. Our goal is to enable the widest possible audience of international
cooperators to successfully download the satellite’s real time scientific payload. The
discussion above and attached pseudocode should help make that possible.
References:
[1] Landsat Data Continuity Mission (LDCM) Spacecraft‐To‐Ground Interface Control Document,
70‐P58230P, Rev C, Orbital Sciences Corporation (ODC), Space Systems Group, Gilbert, AZ,
December 2010.
[2] CCSDS File Delivery Protocol (CFDP), Recommendation for Space Data System Standards,
CCSDS 727.0‐B‐3, Blue Book, June 2005.
[3] H.Garon, V.Sank, D.Fisher, K.Dearth, J.Gal‐Edd and A.Ames, "Successful Use of a High Rate
LDPC Code with High Data Rate in a Restricted Band",CCSDS Spring 2010 Technical Meeting (SLS‐
RFM Working Group), Portsmouth, VA, May 2010.
Figure 2. Basic flow for LDCM CFDP Reader.
Listing for LDCM CFDP Reader Version 1.0
clear;
clc
%%
% Title.........LDCMCFDPreader
% Version ......1.0
% Description...Reads raw data files on output from high data rate (HDR)
% ..............telemetry receiver decoder, extracts up to four embedded
% ..............CCSDS File Delivery Protocol(CFDP) files simultaneously.
% ..............The particular flavor of CFDP is biased towards the Landsat
% ..............Data Continuity Mission (LDCM) as specified in the LDCM
% ..............Spacecraft-To-Ground Interface Control Document.
% Author(s).....H. Garon / V. Sank
% ..............NASA GSFC Code 567
% ..............301-286-4387
% Date..........28 January 2011
% This code may be freely distributed. All we ask is that the authors
% remain identified along with the code, even if the code is substantially
% modified.
%%
Filename_RawData = 'UA L0R_MEDSEA PIE DATA VCALL Thu Jun 17 15.48.13 2010.rec';
%Filename_RawData = 'C INCREMENTING PIE DATA VCALL Thu Jun 17 17.20.04 2010.rec';
fpath_input = 'C:\\Data\\10_06_17 SC_Demod Tests\\';
% Basics
TRUE = 1; FALSE = 0;
% Set debug, output controls
screen = 1;
debug = FALSE;
save_output = TRUE;
verbose = 1;
Report_Frequency = 100;
Report_Count = -1;
dateform = 'yyyymmddHHMMSS';
DTC0 = datestr(now, dateform);
% Maximum CFDP extracted file size for LDCM is
% precisely 1 Gbyte
mxLDCMCFDPfilesize = 1024*1024*1024;
sVCID = strvcat('OLI Real-Time', ...
'TIRS Real-Time', ...
'Playback 1 Mission Data', ...
'Playback 1 SSOH',...
'Playback 2 Mission Data', ...
'Playback 2 SSOH', ...
'Fill');
lutVCID = [0 5 8 10 12 14 63];
Fill_Frame = 63;
sReplayFlag = strvcat('Real-Time Stream', 'Playback from SSR');
sVCusage
= strvcat('not used', 'increment at roll-over');
sPDUtype
= strvcat('File Directive','File Data');
sDirection = strvcat('Toward file receiver','1');
sXmtMode
= strvcat('0','Unacknowledged');
sCRCflag
= strvcat('CRC not present', 'CRC available');
sSrcEntity = strvcat('OLI Instrument','TIRS Instrument', ' ','Ancillary Data Only');
sAPID = strvcat('OLI CFDP Metadata PDU','OLI CFDP End-Of-File PDU',...
'OLI Line Header', 'OLI CRC', 'OLI Frame Header', 'Ancillary Data',...
'OLI Pixels-PAN1_ODD-Compressed','OLI Pixels-PAN1_EVEN-Compressed',...
'OLI Pixels-BLUE_Compressed','OLI Pixels-C/A-Compressed','OLI Pixels-NIR-Compressed',...
'OLI Pixels-RED_Compressed','OLI Pixels-GREEN-Compressed',...
'OLI Pixels-PAN2_ODD_Compressed','OLI Pixels-PAN2_EVEN_Compressed',...
'OLI Pixels-SWIR2_Compressed','OLI Pixels-SWIR1-Compressed',...
'OLI Pixels-CIRRUS_Compressed','OLI Pixels-DARK-Compressed',...
'OLI Pixels-PAN1_ODD-Uncompressed','OLI Pixels-PAN1_EVEN-Uncompressed',...
'OLI Pixels-BLUE_Uncompressed','OLI Pixels-C/A-Uncompressed','OLI Pixels-NIR-Uncompressed',...
'OLI Pixels-RED_Uncompressed','OLI Pixels-GREEN-Uncompressed',...
'OLI Pixels-PAN2_ODD_Uncompressed','OLI Pixels-AN2_EVEN_Uncompressed',...
'OLI Pixels-SWIR2_Uncompressed','OLI Pixels-SWIR1-Uncompressed',...
'OLI Pixels-CIRRUS_Uncompressed','OLI Pixels-DARK-Uncompressed',...
'TIRS CFDP Metadata PDU','TIRS CFDP End-Of-File PDU',...
'TIRS Line Header', 'TIRS CRC', 'TIRS Pixels 10.8 um', 'TIRS Pixels DARK', 'TIRS Pixels 12 um',...
'Reserved', 'Reserved', 'Reserved', 'Reserved', 'Reserved',...
'Reserved', 'Reserved', 'Reserved', 'Reserved', 'Reserved',...
'Reserved', 'Reserved', 'Reserved', 'Reserved', 'Reserved', ...
'Fill Packet');
lutAPID = [0 1 2 3 4 5 ...
256 257 258 259 260 261 262 263 264 265 266 267 268 ...
768 769 770 771 772 773 774 775 776 777 778 779 780 ...
1024 1025 1026 1027 1792 1793 1794 ...
2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 ...
2047];
sFileReadErrors = strvcat('No read errors','Premature end-of-file');
x00
x01
x03
x0F
x2E
x35
x3F
x53
x7F
x80
x1A
x1D
xCF
xF0
xF8
xFC
xFF
x0FA
x7FF
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
uint8(0);
uint8(1);
uint8(3);
uint8(15);
uint8(hex2dec('2e'));
uint8(hex2dec('35'));
uint8(hex2dec('3f'));
uint8(hex2dec('53'));
uint8(hex2dec('7f'));
uint8(hex2dec('80'));
uint8(hex2dec('1a'));
uint8(hex2dec('1d'));
uint8(hex2dec('cf'));
uint8(hex2dec('f0'));
uint8(hex2dec('f8'));
uint8(hex2dec('fc'));
uint8(255);
uint8(250);
uint16(2047);
% Hierarchy
ASM1 = [x1A
Length_ASM1
ASM2 = [x35
Length_ASM2
...
xCF xFC x1D];
= length(ASM1);
x2E xF8 x53];
= length(ASM2);
Length_XferFrameDataField = 1024;
M_PDUhdr = [x00 x00];
Length_M_PDUhdr = length(M_PDUhdr);
Length_M_PDU = 2;
Length_M_PDU_PacketZone = Length_XferFrameDataField - Length_M_PDU;
XferFramePrimaryHdr = [x00 x00 x00 x00 x00 x00];
Length_XferFramePrimaryHdr = length(XferFramePrimaryHdr);
SpacePacketPrimaryHdr = [x00 x00 x00 x00 x00 x00];
Length_SpacePacketPrimaryHdr = length(SpacePacketPrimaryHdr);
CFDPhdr = [x00 x00 x00 x00 x00 x00 x00 x00];
Length_CFDPhdr = length(CFDPhdr);
%SpacecraftID
= uint8(xFC)&bitshift(SpacePacketPrimaryHdr(1),2) ...
%
| (x03&bitshift(SpacePacketPrimaryHdr(2),-6));
CFDPFileDirective = x00;
Length_FileDirectiveCode = length(CFDPFileDirective);
EndOfFilePDU = [x00 x00 x00 x00 x00 x00 x00 x00 x00];
Flag_EOF_PDU = uint8(4);
Length_FileChecksum = 4;
Length_FileSize = 4;
Length_EndOfFilePDU = length(EndOfFilePDU);
MetadataPDU = zeros(1,21,'uint8');
Length_MetadataPDU = length(MetadataPDU);
pOffset = [x00 x00 x00 x00];
Length_Offset = length(pOffset);
MissionDataHdr = [x00 x00 x00 x00];
Length_MissionDataHdr = length(MissionDataHdr);
% Channel Access Data Unit (CADU) - Basic building block for both OLI and
% TIRS. LDCM CADU has a fixed length of 1034 bytes (8272 bits)
Length_CADU = Length_ASM2 + Length_XferFramePrimaryHdr + Length_XferFrameDataField;
Length_MessageData =
892; %bytes
Length_LDPC_CRC =
128; %bytes
Length_RandomizedLength = 1020; %bytes
% Build byte offset table from ASM2 ...
ASM2_offset = 0;
XferFramePrimaryHdr_offset = Length_ASM2;
XferFrameDataField_offset = XferFramePrimaryHdr_offset + Length_XferFramePrimaryHdr;
M_PDUhdr_offset = XferFrameDataField_offset;
M_PDU_PacketZone_offset = M_PDUhdr_offset + Length_M_PDU;
L8 = Length_CADU;
bfr_uint8 = zeros(1, L8, 'uint8');
% As stated above, LDCM has the capability to transmit up to four virtual
% channels at the same time. This implies separate housekeeping must be
% maintained for each virtual channel in use. These channels have the
% following assigned priorites:
%
a. OLI Real-Time
%
b. TIRS Real-time
%
c. One Virtual Channel on Playback 1
%
d. One Virtual Channel on Playback 2
% Both playback virtual channels can contain either OLI, TIRS, Ancillary
% Data or Stored State of Health (SSOH).
VCID = 0;
index = uint8(0);
mxSimultaneousCFDPfiles = 4;
for index = 1:mxSimultaneousCFDPfiles
VC(index).indexVCID = 0;
VC(index).VCID = VCID;
VC(index).Task = 'Space Packet Primary Header';
VC(index).CFDPfileID = 0;
VC(index).CFDPextractedfile = sprintf('%02i_%s_%s.bin', VCID, sVCID(3,:),DTC0);
VC(index).CFDPlogID = 0;
VC(index).CFDPlog = sprintf('%02i_%s_%s.log', VCID, sVCID(3,:),DTC0);
VC(index).nbyteswritten = 0;
VC(index).nbytesCFDP = 0;
VC(index).BytesRemaining = 0;
VC(index).BytesRemaining_MissionData = 0;
VC(index).Length_HDR = 0;
VC(index).SPoffset = 0;
VC(index).SpacePacketPrimaryHdr = SpacePacketPrimaryHdr;
VC(index).CFDPoffset = 0;
VC(index).CFDPhdr = CFDPhdr;
VC(index).CFDPFDoffset = 0;
VC(index).CFDPFileDirective = CFDPFileDirective;
VC(index).MetadataOffset = 0;
VC(index).MetadataPDU = MetadataPDU;
VC(index).EOFPDUoffset = 0;
VC(index).EndOfFilePDU = EndOfFilePDU;
VC(index).Flag_EOF_PDU = Flag_EOF_PDU;
VC(index).OFFSEToffset = 0;
VC(index).pOffset = pOffset;
VC(index).MDHoffset = 0;
VC(index).MissionDataHdr = MissionDataHdr;
VC(index).APIDcount = zeros(1,length(lutAPID));
VC(index).buffer = zeros(1, L8, 'uint8');
end
nASM = 0;
FileReadError = 0;
FileProcessComplete = FALSE;
ReadCounter = 0;
% Open Filename_RawData as directed by user (found at the very beginning of
% this code)
input_file = sprintf('%s%s',fpath_input,Filename_RawData);
fid = fopen(input_file,'r');
CADU_index = 0;
%CADU_index = 337051;
%'C INCREMENTING PIE DATA VCALL Thu Jun 17 17.20.04 2010.rec'
CADU_index = 321365;
%'UA L0R_MEDSEA PIE DATA VCALL Thu Jun 17 15.48.13 2010.rec'
CADU_index_byteseek = CADU_index*Length_CADU;
status = fseek(fid, CADU_index_byteseek, 'bof');
% Extract the CFDP file (or files). Execution terminates upon encountering
% an end-of-file within the raw data input file.
indexVCIDprevious = -1;
SequenceCount = 0;
while(~FileProcessComplete)
% Read raw goop into buffer - should be a chunk (in bytes)at least the
% size of a CADU
bfr_uint8 = fread(fid, L8, 'uint8');
if(feof(fid))
FileProcessComplete = TRUE;
break;
end
ReadCounter = ReadCounter + 1;
% Search for ASM
CADU_found = FALSE;
ASM2_offset = 0;
for i = 1:L8-Length_ASM2
j = i;
for k = 1:Length_ASM2
if(bfr_uint8(j) ~= ASM2(k))
break;
end
j = j + 1;
end
if(k == Length_ASM2)
ASM2_offset = i;
CADU_found = TRUE;
break;
end
end
if(~CADU_found)
% If you encounter this, it's reasonable to stop processing and
% declare the error
fprintf(screen,'\n');
fprintf(screen,'ERROR: ASM (0x352ef853)not detected after CADU %i.\n',CADU_index);
fprintf(screen,'
This could imply that the input file is corrupt.\n');
FileProcessComplete = TRUE;
break;
end
if(CADU_found)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
Transfer Frame primary header
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
XferFramePrimaryHdr_offset = ASM2_offset + Length_ASM2;
for i = 1:Length_XferFramePrimaryHdr
XferFramePrimaryHdr(i) = bfr_uint8(XferFramePrimaryHdr_offset+i-1);
end
MasterChIDVersion = bitand(x03,bitshift(XferFramePrimaryHdr(1),-6));
SCID
= bitor(bitand(xFC,bitshift(XferFramePrimaryHdr(1),2)), ...
bitand(x03,bitshift(XferFramePrimaryHdr(2),-6)));
VCID
= bitand(x3F,XferFramePrimaryHdr(2));
VCframecount
= uint32(256*((256*XferFramePrimaryHdr(3))+XferFramePrimaryHdr(4))+XferFramePrimaryHdr(5));
ReplayFlag
= bitand(x01,bitshift(XferFramePrimaryHdr(6),-7));
VCusage
= bitand(x01,bitshift(XferFramePrimaryHdr(6),-6));
Spare_SF
= bitand(x03,bitshift(XferFramePrimaryHdr(6),-4));
VCframecountCycle = bitand(x0F,XferFramePrimaryHdr(6));
XferFrameDataField_offset = XferFramePrimaryHdr_offset + Length_XferFramePrimaryHdr;
% Fill frame (VCID = 63) is used explicitly to maintain contact
% consistency. If this is a fill frame then there's (almost)
% nothing to do. We first consider all other possible VCIDs ...
if(VCID ~= Fill_Frame)
for indexVCID = 1:length(lutVCID)
if(VCID == lutVCID(indexVCID))
break;
end
end
indexFound = FALSE;
indexNotInUse = FALSE;
if(indexVCID ~= indexVCIDprevious)
% Virtual Channel already in use?
for index = 1:mxSimultaneousCFDPfiles
if(VC(index).indexVCID == indexVCID)
indexFound = TRUE;
break;
end
end
% If not already in play then attempt to assign new Virtual
% Channel
if(~indexFound)
for index = 1:mxSimultaneousCFDPfiles
if(VC(index).indexVCID == 0)
indexNotInUse = TRUE;
break;
end
end
if(~indexNotInUse)
% If you now encounter this, it's again reasonable to stop processing
% and declare an error ...
fprintf(screen,'\n');
fprintf(screen,'ERROR: Only %i Virtual Channels are allowed
simultaneously\n',mxSimultaneousCFDPfiles);
fprintf(screen,'
with this code. An attempt has been made to open a new\n');
fprintf(screen,'
Virtual Channel without completing a previously engaged\n');
fprintf(screen,'
extraction. This could imply that the input file is corrupt.\n');
FileProcessComplete = TRUE;
break;
end
end
if(indexNotInUse)
VC(index).VCID = VCID;
VC(index).indexVCID = indexVCID;
% Open detailed log at the beginning of extraction
DTC0 = datestr(now, dateform);
VC(index).CFDPlog
= sprintf('%02i_%s_%s.log', VCID, strtrim(sVCID(indexVCID,:)),DTC0);
VC(index).CFDPlogID = fopen(VC(index).CFDPlog, 'a+');
SpacecraftID = '';
if(SCID == x0FA)
SpacecraftID = 'LDCM';
end
fprintf(VC(index).CFDPlogID, '\n>> CADU index
: %i\n',CADU_index);
fprintf(VC(index).CFDPlogID, '[Transfer Frame Primary Header]\n');
fprintf(VC(index).CFDPlogID, ' Master Channel ID Version : %02i\n', MasterChIDVersion);
fprintf(VC(index).CFDPlogID, ' SCID
: 0x%03x (%s)\n', SCID, SpacecraftID);
fprintf(VC(index).CFDPlogID, ' VCID
: %02i %s\n', VCID, sVCID(indexVCID,:));
fprintf(VC(index).CFDPlogID, ' VC frame count
: %06i\n', VCframecount);
fprintf(VC(index).CFDPlogID, ' Replay flag
: %s\n', sReplayFlag((ReplayFlag+1),:));
fprintf(VC(index).CFDPlogID, ' VC usage
: %s\n', sVCusage((VCusage+1),:));
fprintf(VC(index).CFDPlogID, ' VC frame count cycle
: %i\n', VCframecountCycle);
end
end
indexVCIDprevious = indexVCID;
VC(index).buffer = uint8(bfr_uint8);
%//////////////////////////////////////////////////////////////////////////
%/
M_PDU header
/
%//////////////////////////////////////////////////////////////////////////
M_PDUhdr_offset
= XferFrameDataField_offset;
M_PDUhdr(1)
= VC(index).buffer(M_PDUhdr_offset+0);
M_PDUhdr(2)
= VC(index).buffer(M_PDUhdr_offset+1);
Spare_M_PDUhdr
= bitand(uint8(hex2dec('1F')),bitshift(M_PDUhdr(1),-3));
FirstHdrPointer
= uint16(256*uint16(bitand(uint8(7),M_PDUhdr(1)))) ...
+ uint16(M_PDUhdr(2));
M_PDU_PacketZone_offset = M_PDUhdr_offset + Length_M_PDUhdr;
%
%
%
%
%
%
%
%
%
%
%
%
%
Processing splits at this point based upon precedents. Literally.
The ASM, Transfer Frame Primary Header and the M_PDU Header
are always self-contained and aligned within a single CADU.
All the remaining headers and data can split across multiple
CADUs. The simplest case occurs where there are no headers
following the M_PDU for the remainder of the CADU. A
FirstHdrPointer = 0x7FF within the M_PDU Header serves as a
flag for precisely that case. With FirstHdrPointer = 0x7FF
all that's necessary is to update counters and store the
remainder of the CADU. Most of the code below supports the
much more complicated case where there is at least one header
embedded in the remaining bytes of the CADU. Handling a split
header or fixed length PDU properly becomes the driving force
% behind the housekeeping.
%
% Handle special case where there are no headers defined in the
% CADU. This is when the FirstHdrPointer = 0x7FF (2047 decimal).
if((FirstHdrPointer == x7FF)&&(VC(index).BytesRemaining == 0))
% Nothing much to do but stuff bytes into current CFDP file being extracted...
if(VC(index).CFDPlogID > 0)
fprintf(VC(index).CFDPlogID, '[M_PDU Packet Header]\n');
fprintf(VC(index).CFDPlogID, ' 1st Header Offset (bytes) : No packet header in zone\n');
fprintf(VC(index).CFDPlogID, ' Mission data (bytes remaining) = %i\n',
VC(index).BytesRemaining_MissionData);
end
if(VC(index).BytesRemaining_MissionData > 0)
VC(index).BytesRemaining_MissionData = VC(index).BytesRemaining_MissionData ...
- (L8 - (M_PDU_PacketZone_offset-1));
end
else
if(VC(index).CFDPlogID > 0)
fprintf(VC(index).CFDPlogID, '[M_PDU Packet Header]\n');
fprintf(VC(index).CFDPlogID, ' 1st Header Offset (bytes) : %i\n', FirstHdrPointer);
fprintf(VC(index).CFDPlogID, ' Mission data (bytes remaining) = %i\n',
VC(index).BytesRemaining_MissionData);
end
VC(index).SPoffset = 0;
ContinuousLoop = TRUE;
while (ContinuousLoop)
switch VC(index).Task
case 'Space Packet Primary Header'
%////////////////////////////////////////////////////////////////////////
%/
Space Packet Primary Header
/
%////////////////////////////////////////////////////////////////////////
% Multiple Space Packet Primary Headers can
% occur within a single CADU. Using a pre-set
% offset (SPoffset > 0) as a flag signals that
% possibility ...
if(VC(index).SPoffset == 0)
VC(index).SPoffset = M_PDU_PacketZone_offset+FirstHdrPointer;
end
VC(index).Length_HDR = Length_SpacePacketPrimaryHdr;
if(VC(index).BytesRemaining > 0)
VC(index).SPoffset = M_PDU_PacketZone_offset;
VC(index).Length_HDR = VC(index).BytesRemaining;
end
if((VC(index).SPoffset+VC(index).Length_HDR -1) <= L8)
i = Length_SpacePacketPrimaryHdr-VC(index).Length_HDR+1;
for j = 1:VC(index).Length_HDR
VC(index).SpacePacketPrimaryHdr(i) = VC(index).buffer(VC(index).SPoffset+j-1);
i = i + 1;
end
SpacePktVersion = bitand(uint8(7),bitshift(VC(index).SpacePacketPrimaryHdr(1),-5));
SpacePktType
= bitand(x01,bitshift(VC(index).SpacePacketPrimaryHdr(1),-4));
SecHdrFlag
= bitand(x01,bitshift(VC(index).SpacePacketPrimaryHdr(1),-3));
APID
=
uint16(256*uint16(bitand(uint8(7),VC(index).SpacePacketPrimaryHdr(1)))) ...
+ uint16(VC(index).SpacePacketPrimaryHdr(2));
SpacePktSeqFlags = bitand(x03,bitshift(VC(index).SpacePacketPrimaryHdr(3),-6));
SpacePktSeqCount = uint16(256*uint16(bitand(x3F,VC(index).SpacePacketPrimaryHdr(3))))
...
+ uint16(VC(index).SpacePacketPrimaryHdr(4));
SpacePacketLength= uint16(256*uint16(VC(index).SpacePacketPrimaryHdr(5))) +
uint16(VC(index).SpacePacketPrimaryHdr(6));
for indexAPID = 1:length(lutAPID)
if(APID == lutAPID(indexAPID))
break;
end
end
% A Space Packet can span multiple M_PDUs or one
% M_PDU can contain multiple Space Packets.
if(VC(index).CFDPlogID > 0)
fprintf(VC(index).CFDPlogID, '[Space Packet Primary Header]\n');
fprintf(VC(index).CFDPlogID, ' Space Packet Version
: %i\n',
SpacePktVersion);
fprintf(VC(index).CFDPlogID, ' Space Packet Type
: %i\n', SpacePktType);
fprintf(VC(index).CFDPlogID, ' Secondary Header Flag
: %i\n', SecHdrFlag);
fprintf(VC(index).CFDPlogID, ' APID
: %04i %s\n', APID,
sAPID(indexAPID,:));
fprintf(VC(index).CFDPlogID, ' Space Packet Seq Flags
: %i\n',
SpacePktSeqFlags);
fprintf(VC(index).CFDPlogID, ' Space Packet Seq Count
: %i\n',
SpacePktSeqCount);
fprintf(VC(index).CFDPlogID, ' Space Packet Length
: %i\n',
SpacePacketLength);
end
if(APID == 0)
%Metadata PDU
% First check to see if we've completely wrapped
% previous CFDP file ...
if(VC(index).CFDPfileID > 0)
% If VC(index).CFDPfileID exists (> 0) then there is an error
fprintf(screen,'\n');
fprintf(screen,'ERROR: Second Metadata PDU (APID = 0) encountered prior to\n');
fprintf(screen,'
detecting the end-of-file PDU (APID = 1). This\n');
fprintf(screen,'
implies either the file is corrupt or there is\n');
fprintf(screen,'
a read error.\n');
FileReadError = 1;
FileProcessComplete = TRUE;
break;
end
%//////////////////////////////////////////////////////////////////////////
% Initiate construction of an encapsulated CFDP file.
% CFDP involves the transmission of Protocol Data Units (PDUs).
% Sequence of transmission follows:
%
a. Metadata PDU (APID = 0)
%
b. File Data PDUs (possibly spanning multiple CADUs)
%
c. EOF PDU (APID = 1)
% The first useable CADU within the search file will employ
% an APID = 0000. This designates a CFDP Metadata PDU.
% This is your hint to start piecing together the
% encapsulated data file. You should also be aware that no
% attempt is made to align a PDU with the CCSDS frame.
% "BytesRemaining" is a key housekeeping variable used
% to keep track of the number of bytes required to complete
% a header across multiple CADUs.
%//////////////////////////////////////////////////////////////////////////
VC(index).CFDPextractedfile = sprintf('%02i_%s_%s.bin', VC(index).VCID,
strtrim(sVCID(VC(index).indexVCID,:)),DTC0);
VC(index).CFDPfileID = fopen(VC(index).CFDPextractedfile, 'a+');
VC(index).APIDcount = zeros(1,length(lutAPID));
VC(index).nbyteswritten = 0;
if(VC(index).CFDPlogID > 0)
fprintf(VC(index).CFDPlogID, '>> CADU index
: %i\n',CADU_index);
fprintf(VC(index).CFDPlogID, '[Transfer Frame Primary Header]\n');
fprintf(VC(index).CFDPlogID, ' Master Channel ID Version : %02i\n',
MasterChIDVersion);
fprintf(VC(index).CFDPlogID, '
fprintf(VC(index).CFDPlogID, '
VC(index).VCID, sVCID(VC(index).indexVCID,:));
fprintf(VC(index).CFDPlogID, '
VCframecount);
fprintf(VC(index).CFDPlogID, '
sReplayFlag((ReplayFlag+1),:));
fprintf(VC(index).CFDPlogID, '
sVCusage((VCusage+1),:));
fprintf(VC(index).CFDPlogID, '
VCframecountCycle);
end
end
SCID
VCID
: 0x%03x\n', SCID);
: %02i %s\n',
VC frame count
: %06i\n',
Replay flag
: %s\n',
VC usage
: %s\n',
VC frame count cycle
: %i\n',
% Update the APID incidence counter
VC(index).APIDcount(indexAPID) = VC(index).APIDcount(indexAPID) + 1;
VC(index).Task = 'CFDP Header';
VC(index).BytesRemaining = 0;
else
% Space Packet primary header is split across two M_PDUs
VC(index).Task = 'Space Packet Primary Header';
VC(index).BytesRemaining = (VC(index).SPoffset+Length_SpacePacketPrimaryHdr-1) - L8;
i = 1;
for j = VC(index).SPoffset:L8
VC(index).SpacePacketPrimaryHdr(i) = VC(index).buffer(j);
i = i + 1;
end
break;
%Forces exit from while loop
end
case 'CFDP Header'
%////////////////////////////////////////////////////////////////////////
%/
CFDP header
/
%////////////////////////////////////////////////////////////////////////
VC(index).CFDPoffset = VC(index).SPoffset + VC(index).Length_HDR;
VC(index).Length_HDR = Length_CFDPhdr;
if(VC(index).BytesRemaining > 0)
VC(index).CFDPoffset = M_PDU_PacketZone_offset;
VC(index).Length_HDR = VC(index).BytesRemaining;
end
if((VC(index).CFDPoffset+VC(index).Length_HDR-1) <= L8)
i = Length_CFDPhdr-VC(index).Length_HDR+1;
for j = 1:VC(index).Length_HDR
VC(index).CFDPhdr(i) = VC(index).buffer(VC(index).CFDPoffset+j-1);
i = i + 1;
end
CFDPversion
= bitand(uint8(7),bitshift(VC(index).CFDPhdr(1),-5));
PDUtype
= bitand(uint8(1),bitshift(VC(index).CFDPhdr(1),-4));
Direction
= bitand(uint8(1),bitshift(VC(index).CFDPhdr(1),-3));
XmissionMode
= bitand(uint8(1),bitshift(VC(index).CFDPhdr(1),-2));
CRCflag
= bitand(uint8(1),bitshift(VC(index).CFDPhdr(1),-1));
Rsrv0_CFDP
= bitand(uint8(1),VC(index).CFDPhdr(1));
PDUdatalength
= uint16(256*uint16(VC(index).CFDPhdr(2))) +
uint16(VC(index).CFDPhdr(3));
Rsrv1_CFDP
= bitand(uint8(1),bitshift(VC(index).CFDPhdr(4),-7));
EntityID_Length = bitand(uint8(7),bitshift(VC(index).CFDPhdr(4),-4));
Rsrv2_CFDP
= bitand(uint8(1),bitshift(VC(index).CFDPhdr(4),-3));
TransSeq_Length = bitand(uint8(7),VC(index).CFDPhdr(4));
SourceEntityID = VC(index).CFDPhdr(5);
TransSeqNum
= uint16(256*uint16(VC(index).CFDPhdr(6))) +
uint16(VC(index).CFDPhdr(7));
DestEntityID
= VC(index).CFDPhdr(8);
if(VC(index).CFDPlogID > 0)
fprintf(VC(index).CFDPlogID, '[CFDP File Data PDU]\n');
fprintf(VC(index).CFDPlogID, ' CFDP version
fprintf(VC(index).CFDPlogID, ' PDU type
: %i\n', CFDPversion);
: %s\n',
fprintf(VC(index).CFDPlogID, '
Direction
: %s\n',
fprintf(VC(index).CFDPlogID, '
Xmission Mode
: %s\n',
fprintf(VC(index).CFDPlogID, '
CRC flag
: %s\n',
sPDUtype(PDUtype+1,:));
sDirection(Direction+1,:));
sXmtMode(XmissionMode+1,:));
sCRCflag(CRCflag+1,:));
fprintf(VC(index).CFDPlogID, ' PDU data length
: %i\n', PDUdatalength);
switch APID
case 0
fprintf(VC(index).CFDPlogID, '
*length = File Directive + Metadata
PDU\n');
case 1
fprintf(VC(index).CFDPlogID, '
otherwise
fprintf(VC(index).CFDPlogID, '
*length = File Directive + EOF PDU\n');
*length = Offset HDR + MDH + File
Data\n');
end
if(APID ~= 2047)
fprintf(VC(index).CFDPlogID, '
Entity ID Length
: %i\n',
fprintf(VC(index).CFDPlogID, '
Transaction Seq Length
: %i\n',
fprintf(VC(index).CFDPlogID, '
SourceEntityID
: %s\n',
fprintf(VC(index).CFDPlogID, '
Transaction Sequence #
: 0x%x\n',
fprintf(VC(index).CFDPlogID, '
Destination Entity ID
: 0x%x\n',
EntityID_Length);
TransSeq_Length);
sSrcEntity(SourceEntityID+1,:));
TransSeqNum);
DestEntityID);
end
end
VC(index).Task = 'Offset';
if((APID == 0) ||(APID == 1))
VC(index).Task = 'CFDP File Directive';
end
VC(index).BytesRemaining = 0;
else
% CFDP header is split across two M_PDUs
VC(index).Task = 'CFDP Header';
VC(index).BytesRemaining = (VC(index).CFDPoffset+Length_CFDPhdr-1) - L8;
i = 1;
for j = VC(index).CFDPoffset:L8
VC(index).CFDPhdr(i) = VC(index).buffer(j);
i = i + 1;
end
break;
%Forces exit from while loop
end
case 'Offset'
%////////////////////////////////////////////////////////////////////////
%/
Offset
/
%////////////////////////////////////////////////////////////////////////
VC(index).OFFSEToffset = VC(index).CFDPoffset + VC(index).Length_HDR;
VC(index).Length_HDR = Length_Offset;
if(VC(index).BytesRemaining > 0)
VC(index).OFFSEToffset = M_PDU_PacketZone_offset;
VC(index).Length_HDR = VC(index).BytesRemaining;
end
if((VC(index).OFFSEToffset+VC(index).Length_HDR -1) <= L8)
i = Length_Offset-VC(index).Length_HDR+1;
for j = 1:VC(index).Length_HDR
VC(index).pOffset(i) = VC(index).buffer(VC(index).OFFSEToffset+j-1);
i = i + 1;
end
vOffset =
uint32(256*(256*(256*VC(index).pOffset(1)+VC(index).pOffset(2))+VC(index).pOffset(3))+VC(index).pOffset(4));
if(verbose > 0)
fprintf(VC(index).CFDPlogID, ' Offset (bytes)
: %i\n', vOffset);
end
VC(index).Task = 'Mission Data Header';
VC(index).BytesRemaining = 0;
else
% Offset is split across two M_PDUs
VC(index).Task = 'Offset';
VC(index).BytesRemaining = (VC(index).OFFSEToffset+Length_Offset-1) - L8;
i = 1;
for j = VC(index).OFFSEToffset:L8
VC(index).pOffset(i) = VC(index).buffer(j);
i = i + 1;
end
break;
%Forces exit from while loop
end
case 'Mission Data Header'
%////////////////////////////////////////////////////////////////////////
%/
Mission Data Header
/
%////////////////////////////////////////////////////////////////////////
VC(index).MDHoffset = VC(index).OFFSEToffset + VC(index).Length_HDR;
VC(index).Length_HDR = Length_MissionDataHdr;
if(VC(index).BytesRemaining > 0)
VC(index).MDHoffset = M_PDU_PacketZone_offset;
VC(index).Length_HDR = VC(index).BytesRemaining;
end
if((VC(index).MDHoffset+VC(index).Length_HDR -1) <= L8)
i = Length_MissionDataHdr-VC(index).Length_HDR+1;
for j = 1:VC(index).Length_HDR
VC(index).MissionDataHdr(i) = VC(index).buffer(VC(index).MDHoffset+j-1);
i = i + 1;
end
CFDP_APID
= uint16(256*uint16(bitand(uint8(7),VC(index).MissionDataHdr(1))))
...
+ uint16(VC(index).MissionDataHdr(2));
MissionDataLength = uint16(256*uint16(VC(index).MissionDataHdr(3))) ...
+ uint16(VC(index).MissionDataHdr(4));
for i = 1:length(lutAPID)
if(CFDP_APID == lutAPID(i))
break;
end
end
if(VC(index).CFDPlogID > 0)
fprintf(VC(index).CFDPlogID, '[Mission Data Header]\n');
fprintf(VC(index).CFDPlogID, ' CFDP APID
: %04i %s\n', CFDP_APID,
sAPID(i,:));
fprintf(VC(index).CFDPlogID, '
Mission Data Length
: %i\n',
MissionDataLength);
end
% Anticipate the next space packet primary header
VC(index).Task = 'Space Packet Primary Header';
VC(index).SPoffset = MissionDataLength + (VC(index).MDHoffset+VC(index).Length_HDR);
VC(index).BytesRemaining = 0;
VC(index).BytesRemaining_MissionData = 0;
if(VC(index).SPoffset > L8)
VC(index).BytesRemaining_MissionData = (VC(index).SPoffset-1) - L8;
VC(index).SPoffset = 0;
break;
end
else
% Mission Data Header is split across two M_PDUs
VC(index).Task = 'Mission Data Header';
VC(index).BytesRemaining = (VC(index).MDHoffset+Length_MissionDataHdr-1) - L8;
i = 1;
for j = VC(index).MDHoffset:L8
VC(index).MissionDataHdr(i) = VC(index).buffer(j);
i = i + 1;
end
break;
%Forces exit from while loop
end
case 'CFDP File Directive'
%////////////////////////////////////////////////////////////////////////
%/
CFDP File Directive
/
%////////////////////////////////////////////////////////////////////////
VC(index).CFDPFDoffset = VC(index).CFDPoffset + VC(index).Length_HDR;
VC(index).Length_HDR = Length_FileDirectiveCode;
if(VC(index).BytesRemaining > 0)
VC(index).CFDPFDoffset = M_PDU_PacketZone_offset;
VC(index).Length_HDR = VC(index).BytesRemaining;
end
if(VC(index).CFDPFDoffset <= L8)
VC(index).CFDPFileDirectiveCode = VC(index).buffer(VC(index).CFDPFDoffset);
if(verbose > 0)
fprintf(VC(index).CFDPlogID, ' File Directive Code
: 0x%02x\n',
VC(index).CFDPFileDirectiveCode);
end
switch VC(index).CFDPFileDirectiveCode
case 4
VC(index).Task = 'End-Of-File PDU';
case 7
VC(index).Task = 'Metadata PDU';
otherwise
VC(index).Task = 'Metadata PDU';
if(APID == 1)
VC(index).Task = 'End-Of-File PDU';
end
end
VC(index).BytesRemaining = 0;
else
% Just ran out of room for a single byte...
VC(index).Task = 'CFDP File Directive';
VC(index).BytesRemaining = 1;
break;
%Forces exit from while loop
end
case 'Metadata PDU'
%////////////////////////////////////////////////////////////////////////
%/
Metadata PDU
/
%////////////////////////////////////////////////////////////////////////
VC(index).MetadataOffset = VC(index).CFDPFDoffset + VC(index).Length_HDR;
VC(index).Length_HDR = Length_MetadataPDU;
if(VC(index).BytesRemaining > 0)
VC(index).MetadataOffset = M_PDU_PacketZone_offset;
VC(index).Length_HDR = VC(index).BytesRemaining;
end
if((VC(index).MetadataOffset+VC(index).Length_HDR-1) <= L8)
i = Length_MetadataPDU-VC(index).Length_HDR+1;
for j = 1:VC(index).Length_HDR
MetadataPDU(i) = VC(index).buffer(VC(index).MetadataOffset+j-1);
i = i + 1;
end
SegControl
= (bitand(x80,MetadataPDU(1))~=0);
Rsvd_MD
= bitand(x7F,MetadataPDU(1));
FileSize_MD
=
uint32(256*(256*(256*MetadataPDU(2)+MetadataPDU(3))+MetadataPDU(4))+MetadataPDU(5));
SRCnamelength = MetadataPDU(6);
SRCfilename
= char(MetadataPDU(7:13));
DESnamelength = MetadataPDU(14);
DESfilename
= char(MetadataPDU(15:21));
if(VC(index).CFDPlogID > 0)
fprintf(VC(index).CFDPlogID, '[CFDP Metadata PDU]\n');
fprintf(VC(index).CFDPlogID, ' Segmentation Control
: %i\n', SegControl);
fprintf(VC(index).CFDPlogID, ' Source filename
: %s\n', SRCfilename);
fprintf(VC(index).CFDPlogID, ' Destination filename
: %s\n', DESfilename);
end
VC(index).Task = 'Space Packet Primary Header';
VC(index).SPoffset = VC(index).MetadataOffset+VC(index).Length_HDR;
VC(index).BytesRemaining = 0;
else
% Store what remains of buffer ...
VC(index).Task = 'Metadata PDU';
VC(index).BytesRemaining = (VC(index).MetadataOffset+VC(index).Length_HDR-1) - L8;
i = 1;
for j = VC(index).MetadataOffset:L8
MetadataPDU(i) = VC(index).buffer(j);
i = i + 1;
end
break;
%Forces exit from while loop
end
case 'End-Of-File PDU'
%////////////////////////////////////////////////////////////////////////
%/
End-Of-File PDU
/
%////////////////////////////////////////////////////////////////////////
VC(index).EOFPDUoffset = VC(index).CFDPFDoffset + VC(index).Length_HDR;
VC(index).Length_HDR = Length_EndOfFilePDU;
if(VC(index).BytesRemaining > 0)
VC(index).EOFPDUoffset = M_PDU_PacketZone_offset;
VC(index).Length_HDR = VC(index).BytesRemaining;
end
if((VC(index).EOFPDUoffset+VC(index).Length_HDR-1) <= L8)
i = Length_EndOfFilePDU-VC(index).Length_HDR+1;
for j = 1:VC(index).Length_HDR
VC(index).EndOfFilePDU(i) = VC(index).buffer(VC(index).EOFPDUoffset+j-1);
i = i + 1;
end
ConditionCode = bitshift(bitand(xF0,VC(index).EndOfFilePDU(1)),-4);
Spare_EOF
= bitand(x0F,VC(index).EndOfFilePDU(1));
FileChksum
=
uint32(256*(256*(256*VC(index).EndOfFilePDU(2)+VC(index).EndOfFilePDU(3))+VC(index).EndOfFilePDU(4))+VC(index).EndOfFil
ePDU(5));
FileSize
=
uint32(256*(256*(256*VC(index).EndOfFilePDU(6)+VC(index).EndOfFilePDU(7))+VC(index).EndOfFilePDU(8))+VC(index).EndOfFil
ePDU(9));
if(VC(index).CFDPlogID > 0)
fprintf(VC(index).CFDPlogID, '[End Of File PDU]\n');
fprintf(VC(index).CFDPlogID, ' Condition Code
: 0x%02x\n',
ConditionCode);
fprintf(VC(index).CFDPlogID, ' File Check Sum
: 0x%08x\n', FileChksum);
fprintf(VC(index).CFDPlogID, ' File Size (Kbyte)
: %07i\n',
FileSize/1024);
end
VC(index).Task = 'Space Packet Primary Header';
VC(index).SPoffset = VC(index).EOFPDUoffset+VC(index).Length_HDR;
VC(index).BytesRemaining = 0;
else
% Store what remains of buffer ...
VC(index).Task = 'End-Of-File PDU';
VC(index).BytesRemaining = (VC(index).EOFPDUoffset+Length_EndOfFilePDU-1) - L8;
i = 1;
for j = VC(index).EOFPDUoffset:L8
VC(index).EndOfFilePDU(i) = VC(index).buffer(j);
i = i + 1;
end
break;
%Forces exit from while loop
end
end
% End switch
end
% End while loop (that's what the breaks are for within switch)
end
% End CADU read
% If we've been working on building the CFDP file then
% dump the remainder of the block to the file from (and including)
% the M_PDU header. Update counters as well.
if(VC(index).CFDPfileID > 0)
count = fwrite(VC(index).CFDPfileID, VC(index).buffer(M_PDUhdr_offset:L8), 'uint8');
VC(index).nbyteswritten = VC(index).nbyteswritten + count;
VC(index).nbytesCFDP = VC(index).nbytesCFDP + count;
if(VC(index).APIDcount(2) > 0)
if(VC(index).nbyteswritten >= mxLDCMCFDPfilesize)
indexVCIDprevious = -1;
if(VC(index).CFDPlogID > 0)
fprintf(VC(index).CFDPlogID, '\n');
fprintf(VC(index).CFDPlogID, ' Extraction stopped: %s\n', datestr(now, dateform));
fprintf(VC(index).CFDPlogID, ' File statistics: CADU_index
= %i\n', CADU_index );
fprintf(VC(index).CFDPlogID, '
bytes written = %i\n',
VC(index).nbytesCFDP );
for i=1:length(lutAPID)
if(VC(index).APIDcount(i) > 0)
fprintf(VC(index).CFDPlogID, '
APID %04i
= %i\n',
lutAPID(i),VC(index).APIDcount(i));
end
end
if(verbose > 0)
fprintf(screen, '\n');
fprintf(screen, ' Extraction stopped: %s\n', datestr(now, dateform));
fprintf(screen, ' File statistics: CADU_index
= %i\n', CADU_index );
fprintf(screen, '
bytes written = %i\n', VC(index).nbytesCFDP );
for i=1:length(lutAPID)
if(VC(index).APIDcount(i) > 0)
fprintf(screen, '
APID %04i
= %i\n',
lutAPID(i),VC(index).APIDcount(i));
end
end
fprintf(screen, '\n');
end
% Close log file
fclose(VC(index).CFDPlogID);
VC(index).CFDPlogID = 0;
end
if(VC(index).CFDPfileID > 0)
% Close extraction file
fclose(VC(index).CFDPfileID);
VC(index).CFDPfileID = 0;
VC(index).indexVCID = 0;
end
end
end
end
else
%////////////////////////////////////////////////////////////////////////
%/
Fill frame processing - Terminate any CFDP files for
/
%/
which an End-Of-File PDU has been received
/
%/
(APIDcount(2) > 0)
/
%////////////////////////////////////////////////////////////////////////
if(indexVCIDprevious ~= -1)
for index = 1:mxSimultaneousCFDPfiles
FileExtractionStillActive = FALSE;
if(VC(index).indexVCID > 0)
if(VC(index).APIDcount(2) > 0)
if(VC(index).CFDPlogID > 0)
fprintf(VC(index).CFDPlogID, '\n');
fprintf(VC(index).CFDPlogID, ' Extraction stopped: %s\n', datestr(now, dateform));
fprintf(VC(index).CFDPlogID, ' File statistics: CADU_index
= %i\n', CADU_index );
fprintf(VC(index).CFDPlogID, '
bytes written = %i\n',
VC(index).nbytesCFDP );
for i=1:length(lutAPID)
if(VC(index).APIDcount(i) > 0)
fprintf(VC(index).CFDPlogID, '
APID %04i
= %i\n',
lutAPID(i),VC(index).APIDcount(i));
end
end
if(verbose > 0)
fprintf(screen, '\n');
fprintf(screen, ' Extraction stopped: %s\n', datestr(now, dateform));
fprintf(screen, ' File statistics: CADU_index
= %i\n', CADU_index );
fprintf(screen, '
bytes written = %i\n', VC(index).nbytesCFDP );
for i=1:length(lutAPID)
if(VC(index).APIDcount(i) > 0)
fprintf(screen, '
APID %04i
= %i\n',
lutAPID(i),VC(index).APIDcount(i));
end
end
fprintf(screen, '\n');
end
% Close log file
fclose(VC(index).CFDPlogID);
VC(index).CFDPlogID = 0;
end
if(VC(index).CFDPfileID > 0)
% Close extraction file
fclose(VC(index).CFDPfileID);
VC(index).CFDPfileID = 0;
VC(index).indexVCID = 0;
end
else
FileExtractionStillActive = TRUE;
end
end
end
if(~FileExtractionStillActive)
indexVCIDprevious = -1;
end
end
end
CADU_index = CADU_index + 1;
if(verbose > 0)
Report_Count = mod(Report_Count+1,Report_Frequency);
if(Report_Count == 0)
fprintf(screen, 'CADU(index, read): %010i
%010i\n',CADU_index, ReadCounter);
end
end
end
end
fclose(fid);
for index = 1:mxSimultaneousCFDPfiles
if(VC(index).CFDPlogID > 0)
fprintf(VC(index).CFDPlogID, '\n');
fprintf(VC(index).CFDPlogID, ' Extraction stopped: %s\n', datestr(now, dateform));
fprintf(VC(index).CFDPlogID, ' File statistics: CADU_index
= %i\n', CADU_index );
fprintf(VC(index).CFDPlogID, '
bytes written = %i\n', VC(index).nbytesCFDP );
for i=1:length(lutAPID)
if(VC(index).APIDcount(i) > 0)
fprintf(VC(index).CFDPlogID, '
APID %04i
= %i\n',
lutAPID(i),VC(index).APIDcount(i));
end
end
fclose(VC(index).CFDPlogID);
VC(index).CFDPlogID = 0;
if(verbose > 0)
fprintf(screen, '\n');
fprintf(screen, ' Extraction stopped: %s\n', datestr(now, dateform));
fprintf(screen, ' File statistics: CADU_index
= %i\n', CADU_index );
fprintf(screen, '
bytes written = %i\n', VC(index).nbytesCFDP );
for i=1:length(lutAPID)
if(VC(index).APIDcount(i) > 0)
fprintf(screen, '
APID %04i
= %i\n', lutAPID(i),VC(index).APIDcount(i));
end
end
fprintf(screen, '\n');
end
end
if(VC(index).CFDPfileID > 0)
fclose(VC(index).CFDPfileID);
VC(index).CFDPfileID = 0;
VC(index).indexVCID = 0;
end
end
Listing for LDCM CFDP Reader Version 1.0
Download