#!/usr/local/bin/perl 

#########################################################################
#                               ISTP SOFTWARE
#                      Property of the U.S. Government
#                            NASA/GSFC/Code 560
#########################################################################
#
# UNIT NAME:  lzp_split
#
# PURPOSE:  Scans through a file of blocks to make sure all blocks
#           are part of a single message (first 6 header bytes after
#           Nascom sync identical).  If differences found, generates
#           separate files containing separate messages.          
#           Returns name/names of files to be passed on for further
#	    processing.
#
# INVOCATION METHOD:  lzp_split [flags] [[filename] ... ]
#
# ARGUMENT LIST:
# NAME          TYPE                USE  DESCRIPTION
# ------------  ------------------  ---  -------------------------------
# flags         string               I   -d = debug without modifying
#                                        -h = display help screen
#                                        -v = enable verbose mode
#                                        -f = force removal of original
#
# filename      string               I   name of raw data block file
#                                        to scan
#
# EXTERNAL FILE/RECORD REFERENCES:
# /usr/local/bin/perl shell script interpreter
#
# EXTERNAL VARIABLES:
# none
#
# EXTERNAL UNIT/MACRO/PROCEDURE/FUNCTION REFERENCES:
# none
#
# ABNORMAL TERMINATION CONDITIONS, ERROR MESSAGES:
#
# ASSUMPTIONS, CONSTRAINTS, RESTRICTIONS:
# stdout is only for output file names
# stderr is only for messages
#
# CHANGE HISTORY:
# AUTHOR           CHANGE-ID  RELEASE     DATE      DESCRIPTION OF CHANGE
# ---------------  ---------  ----------  --------  ---------------------
# K. Hogie         ISTP       R1.0b       11/17/97  Original code
# R. Wiechert      ISTP       R1.0D       01/27/98  Add diagnostic messages
#                                                    and the force option
# R. Wiechert      ISTP       R1.3        06/30/98  Standard option parsing
#
# NOTES:
# none
#
#########################################################################

require "getopts.pl";

#########################################################################
#       Table of SRC/DST codes and various related text strings
#
#		From Nascom 542-002   
#
#		Digital Data Source/Destination
#			and Format Codes Handbook
#				for the
#		Nascom Message Switching System
#
#		Revision 5  of Oct. 1996
#
#######################################################################

##################################################################
#											
#	Source/Dest	code table format			
#										
#	  Num #	* Org. Ant3	AntDesc	Geo3 GeoDesc
#
#		(fields separated by at least a , (tab,whitespace around is OK))
#											
#		Num		= Octal	Src/Dest code value	
#		#		= Valid	destination	code flag	
#		*		= Valid	source code	flag			
#		Center	= Controlling Center (JPL, WPS,	MILA, etc.)	
#		Ant3	= 3 or 4 character antenna/control center code	
#		Geo3	= 3	or 4 character geographic code for antenna/control center
#		AntDesc	= Long description of antenna/POCC			
#		GeoDesc	= Long description of geographic location	
#
##################################################################
#
# #  D  S  Center Ant Geo  AntDesc  GeoDesc
#
$SRCT = << "E_O_T" ;
0001, #, *, MILA, D79,  MIL, DSS-79, MILA DSS-79
0002, #, *, MILA, S70,  MIL, SPC-70 (Signal Processing Center - MILA), MIL71 
0003, #, *, MILA, D72,  MIL, DSS-72 (MILA), MIL71
0006, #, *, ????,  LM,  CA, ???, Lockheed-Martin Palo Alto; California (GOES I-M), Palo Alto
0007, #, -, JSC,  SPIF, JSC, JSC/SPIF (Payload Commands), JSC/SPIF
0010, #, *, GSFC, AGO,  AGO, AGO, Santiago; Chile (AGO)
0011, #, *, JPL,  C22,  JPL, CTT22 Compatibility Test Trailer (DSN), DSN CTT22
0012, #, *, GSFC, REN,  GSFC, Renaissance Lab, GSFC bldg. 23 E120
0013, #, *, JPL,  APL,  JHU,  JPL-Applied Physics Lab, John Hopkins Univ.
0014, #, *, WFF,  WPS,  WPS,  Wallops - PSATS/Command, Wallops
0015, #, -, JPL,  DSN,  DSN,   S/C OBC Dump Data, DSN Emergency Support
0020, #, *, GSFC, FDF,  GSFC, FDF (Trk and Vector Data), FDF
0023, -, -, JPL,  AMMOS,JPL, AMMOS Simulation Subsystem, JPL - AMMOS
0026, #, *, GSFC, SPIF, GSFC, SPIF (Shuttle-1 GSFC Payload Data/Real-time), GSFC-SPIF
0027, #, *, GSFC, SOC,  SOC,  Simulation Operations Control, GSFC-SOC
0030, #, *, GSFC, NTTF, NTTF, NTTF, Greenbelt (NTTF)
0034, #, *, GSFC, STOCC, GSFC, STOCC (Space Telescope - Playback), GSFC-STOCC
0035, #, *, JPL,  DSN , DSN,  DSN Emergency Support - Real-time Data
0036, -, -, GSFC, NIM,  GSFC,  NIMOCC (Future Nimbus 7) NIM-I, GSFC-NIM??
0040, #, *, GSFC, MSOC, GSFC,  MSOCC IMP Real-time, GSFC-MSOCC
0041, #, *, JPL,  LASH, JPL,  STRV-1A & 1B, JPL - Lasham; England (STRV-1A and 1B)
0043, #, *, ???,  LM,   CA,   GOES Processed TLM, to MSOCC/FDF/GSS Bldg. 6/ Lockheed-Martin Palo Alto
0046, #, *, GSFC, MCE,  MCE, ISTP TPOCC (WIND & POLAR) (Monitor and Command Echo), GSFC-ISTP TPOCC
0047, #, *, JPL,  ESOC, DE,   ICV Data, JPL - ESOCC; Darmstadt, Germany
0051, #, *, GSFC, TIP,  GSFC, MSOCC/TIPIT (ERBS Real-time), GSFC-TIPIT
0052, #, *, GSFC, FAST, GSFC, Small Explorer (FAST), TPOCC
0053, #, *, GSFC, HST,  HST,  STOCC (Space Telescope - R/T), GSFC HST
0054, #, *, GSFC, EUVE, EUVE, Explorer Platform (EUVE) - RTC, GSFC EUVE
0055, -, -, JPL,  D49,  AUS,  DSS-49, Parks, Australia (DSS-49)
0064, #, *, GSFC, SOC,  SOC,  Simulation Operations Control Center (SOCC), GSFC bldg 25
0070, #, -, GSFC, IRT,  IRT,  ICE/IMP Real-time, MSOCC/TIPIT
0074, #, -, GSFC, SMEX, SMEX, SMEX/SAMPEX/TPOCC/IPD, TPOCC/IPD
0075, #, *, GSFC, WPB,  WPB,  ISTP WIND Playback, GGS TPOCC/IPD
0076, #, *, GSFC, RTC,  RTC,  Real-time Control - RTC, MSOCC
0103, #, *, GSFC, NOAA, WFF,  NOAA Tracking Station, Wallops/GOES
0112, #, *, JPL,  ISAS, ISAS, SSOC, ISAS Japan
0115, #, *, GSFC, SAMP, SAMP, SMEX SAMPEX, TPOCC/IPD
0117, #, *, GSFC, FDF,  FDF,  TDRSS Tracking, GSFC FDF
0120, #, *, GSFC, PWI,  PWI,  POLAR IPD PWI Data, GSFC-ISTP
0121, #, *, JPL,  GSOC, JPL,  GSOCC Channel-3, (via JPL)
0123, #, *, JPL,  S04,  DTC,  SPC-04 9M, JPL DTF 21
0125, #, *, JPL,  D05,  DTF,  DSS-05 (34-M STD), JPL DTF 21
0127, #, *, JPL,  S10,  GDS,  SPC-10, (Signal Processing Center - Goldstone)
0133, #, *, JPL,  D06,  DTF,  DSS-06 (70-M), JPL DTF 21
0135, #, *, GSFC, SOH,  SOH,  ISTP SOHO,  TPOCC & IPD
0136, -, -, JPL,  D59,  DE,   DSS-59 15-M Ant #2, Weilheim; Germany 
0137, #, *, JPL,  D07   DTF,  DSS-07 (34-M HEF), JPL DTF 21
0140, #, *, GSFC, WFF,  WFF,  Telemetry/Tracking Data WPSA 9M, Wallops Flight Facility 
0146, #, *, JPL,  D08,  DTF,  DSS 08 (26-M), DTF JPL 21 
0147, -, -, JPL,  D58,  DE,   DSS-58 15-M #1, Germany
0154, #, *, JPL,  TAC1, TOK,  TACC-1, NASDA; Tokyo
0155, #, *, JPL,  TAC2, TOK,  TACC-2, NASDA; Tokyo
0161, -, *, GSFC, D18,  BDA,  DSS-18 BDA, (Source-Only TrackingHigh-Speed - TDPS) DSS-18
0167, #, *, JPL,  NOC, JPL,  NOCC-JPL, (JPL-Network Control)
0170, #, *, JPL,  MSOC, JPL, JPL MSOCC (Playback), JPL Internal MSOCC 
0174, #, -, CNES, FDF, FDF, FDF/CNES (Tracking), FDF/CNES
0175, #, *, 
0177, -, -, JPL,  D03, VLBI,  DSS-03 (OVLBI), DTF-21
0201, #, *, JPL,  D12, GDS,  DSS-12 34M, (Goldstone)
0202, #, *, JPL,  D14, GDS,  DSS-14 70M, (Goldstone)
0203, #, *, JPL,  D15, GDS,  DSS-15 34M, (Goldstone)
0204, #, *, JPL,  D16, GDS,  DSS-16 26M, (Goldstone)
0207, #, -, JSC,  SPIF, JSC, (Payload Commands), JSC/SPIF 
0210, #, -, JPL,  NAV, DSN, (Tracking), DSN NAV & FDF
0216, #, *, JPL,  AGC, AF,  AGC Monitor Blocks, DSN/Air Force 
0220, #, *, JPL,  S40, CAN, SPC-40 (Signal Processing Center, Tidbinbilla)
0221, #, *, JPL,  RAD, RAD, Radarsat, via JPL
0222, #, *, JPL,  D42, CAN, DSS-42 34M, (Tidbinbilla)
0223, #, *, JPL,  D43, CAN, DSS-43 70M, (Tidbinbilla)
0224, #, *, JPL,  D45, CAN, DSS-45 34M, (Tidbinbilla) Tracking Data
0225, #, *, JPL,  D46, CAN, DSS-46 26M, (Tidbinbilla)
0226, #, *, GSFC  SPIF, SPIF, SPIF (Shuttle-2 GSFC Payload Data/Playback), SPIF
0227, -, -, JPL,  D68,  DE,   DSS-68 30-M Ant. #3, Weilheim; Germany 
0230, #, *, GSFC, MPT,  MSOC,  MSOCC (MPT), MSOCC (MPT)
0232, #, *, JPL,  D34,  CAN,  DSS-34,  (Tidbinbilla)
0234, #, *, GSFC, PPB,  PPB,  ISTP POLAR/Playback, TPOCC & IPD
0240, #, *, GSFC, MSOC, MSOC, MSOCC GRO/RTC, MSOCC GRO/RTC
0241, #, *, JPL,  GSOC,  DE, GSOCC Channel 2, GSOCC(Munich; Germany) 
0245, #, -, JSC,  FDF,  FDF, JSC FDF, JSC FDF
0246, #, *, JPL,  GSOC, DE,  GSOCC (Spacelab D-2; Germany 19.2 kbs) SLB-1, GSOCC SLB-1
0247, #, *, JPL,  GSOC, DE,  GSOCC Channel 1, GSOCC (Munich; Germany)
0256, -, -, JPL,  ARC, ARC,  Ames Research Center, Ames Research Center
0257, #, *, JPL,  NAV, NAV,  DSN Navigation, DNS Navigation
0260, #, *, JPL,  TOTS, TOTS, Transportable Orbital Tracking Stations, JPL ???
0267, -, -, JPL,  INT, JPL, Internal use, JPL Internal
0270, #, *, GSFC, SWCE, SWCE, SMEX (SWAS) Cmd/Cmd Echo, TPOCC & MSOCC ICE Cmd/Return
0275, #, *, JPL,  D09,  JPL, DSS-09 (34M BWG), Test Facility
0277, #, *, GSFC, MPT,  GSFC, MPT, MSOCC
0300, #, *, GSFC, SWRT, SWRT, SMEX (SWAS) All Data Rates Telemetry; Monitor Blocks,  TPOCC/PACOR II 
0301, #, *, GSFC, N10, NOAA, NOAA 9/10 Telemetry, IPD
0302, #, *, GSFC, WRT, WRT,  WIND Real-time Tlm, ISTP Wind GGS TPOCC/IPD/SPOF 
0303, #, *, GSFC, W11, WOTS,  11-Meter System, Wallops Orbital Tracking Station (WOTS)
0310, #, *, JPL,  AMM, JPL, JPL-AMMOS, JPL-AMMOS
0311, #, *, JPL,  D24, GDS, DSS-24 (34M BWG) Subnet 1, Goldstone
0312, #, *, JPL,  D25, GDS, DSS-25 (34M BWG) Subnet 2, Goldstone
0313, #, *, JPL,  D26, GDS, DSS-26 (34M BWG) Subnet 3, Goldstone (Internal) & MCC Ground Support Equip. No. 2 (Internal)
0316, -, -, JPL,  D53, MAD,  DSS-53,  Madrid (OVLBI)
0320, -, -, JPL,  CH2, TOPX, Channel 2, TOPEX POCC
0322, #, *, JPL,  CH4, DE,  Channel 4, GSOCC (Munich; Germany)
0324, #, *, GSFC, CMD, GSFC, Small Explorer (SAMPEX), TPOCC DSN Cmd/Tlm
0326, #, *, GSFC, FDF, GSFC, (Test Only), FDF
0327, #, *, JPL, S60, MAD,  SPC-60 (Signal Processing Center, Madrid)
0331, #, *, GSFC, FDF, GSFC, (Test Circuit), FDF
0333, #, *, JPL, D17, GDS, DSS-17 9M, (Goldstone)
0335, #, *, GSFC,MSOC, GSFC, MSOCC/IPD, DSN Emergency Support Playback
0336, #, *, ???, MSOC, ???, MSOCC (Real-time Control), ERBS
0337, *, -, JPL, MPT7, JPL, MSOCC MPT-7, JPL AMMOS (Internal)
0340, #, -, GSFC SWAS, GSFC, Small Explorer (SWAS),  PACOR II
0341, #, *, GSFC, GPB, GSFC, Geotail DSN Playback, ISTP Geotail IPD 
0343, #, *, GSFC, SDPF, GSFC, SDPF, GSFC
0345, -, *, JPL, D62, MAD,  DSS-62 Source Code Only, (Madrid) 
0346, #, *, JPL, D27, GDS,  DSS-27 (34-M BWG-HSB??), Goldstone 
0347, #, *, JPL, D28, GDS,  DSS-28 (34-M BWG), Goldstone 
0350, #, *, JPL,  POC, JPL, (Command), TOPEX POCC
0353, #, *, GSFC, MPT, GSFC, Mission Planning Terminal, GSFC MSOCC
0362, #, *, GSFC, PRT, PRT, GGS POCC POLAR R/T Telemetry IPD Port, ISTP TPOCC/IPD 
0363, #, *, JPL, D61, MAD, DSS-61 34M, (Madrid)
0364, #, *, JPL, D63, MAD, DSS-63 70M, (Madrid)
0365, #, *, JPL, D54, MAD, DSS-54 34M BWG,  (Madrid )
0366, #, *, JPL, D66, MAD, DSS-66 26M, (Madrid)
0375, #, *, JPL, D65, MAD, DSS-65 34M, (Madrid)
E_O_T

for ( $I=0; $I<256 ; $I++ ) {
	$SRC_ANT3[ $I ] = $SRC_GEO3[ $I ] =  sprintf( "0%3.3o", $I) ;
	$SRC_ANTDESC[ $I ] = $SRC_GEODESC[ $I ] = "Undefined" ;
}

@SR = split( /\n/, $SRCT ) ;
$I = 0 ;
while( $SR[ $I ] ) {            # process each line of table information
        @LS=split( /\s*,\s*/, $SR[$I]); # split on commas and any surrounding whitespace
        $INDX                   = oct( $LS[0] ) ;     # get numeric station code
        if( $LS[1] eq "#" ) { $SRC_DSTVALID[ $INDX ] = 1 }
        if( $LS[2] eq "*" ) { $SRC_SRCVALID[ $INDX ] = 1 }
        $SRC_CENTER[ $INDX ]    = $LS[ 3 ] ;    # get controlling center name
        $SRC_IRTS[ $INDX ]      = $LS[4] ;   # 3 char name for building IRTS tables
        $SRC_HASH{ $LS[4] }     = $INDX  ;   # build array to associate name with number
        $SRC_ANT3[ $INDX ]      = $LS[4] ;   # 3 char name
        $SRC_GEO3[ $INDX ]      = $LS[5] ;   # descriptive site name
        $SRC_ANTDESC[ $INDX ]   = $LS[6] ;   # 5 char antenna name
        $SRC_GEODESC[ $INDX ]   = $LS[7] ;   # long antenna name
        $I++ ;
}

for ( $I=0; $I<256 ; $I++ ) {
        $SCID[ $I ] = sprintf( "0%3.3o", $I) ;
}

$SCID[ 0010 ] = "WIND    - Normal" ;
$SCID[ 0011 ] = "WIND    - Simulation" ;
$SCID[ 0015 ] = "POLAR   - Normal" ;
$SCID[ 0016 ] = "POLAR   - Simulation" ;
$SCID[ 0001 ] = "GEOTAIL - Normal" ;
$SCID[ 0025 ] = "SOHO" ;

$PDFT = << "E_O_T" ;
0343, B, RT, WIND,   5.565 Kbps - Science, Maneuver, Contingency (R/T)
0344, A, RT, WIND,   1.113 Kbps - Engineering (R/T)
0345, C, RT, WIND,  11.130 Kbps - 2X-Science, Maneuver, Contingency (R/T)
0342, E, PB, WIND,  64.000 Kbps - Science, Maneuver, Contingency (P/B)
0320, D, PB, WIND,  32.000 Kbps - 1/2-Science, Maneuver, Contingency (P/B)
0321, F, PB, WIND, 128.000 Kbps - 2X-Science, Maneuver, Contingency (P/B)
0322, B, RT, POLAR,  55.650 Kbps - Science, Maneuver, Contingency (R/T)
0323, A, RT, POLAR,   1.113 Kbps - Engineering (R/T)
0325, G, RT, POLAR,  256.000 Kbps - PWI Data (Real-time)
0326, D, PB, POLAR,  512.000 Kbps - Science, Maneuver, Contingency (P/B)
0330, C, PB, POLAR,  256.000 Kbps - 1/2-Science, Maneuver, Contingency (P/B)
0310, A, RT, GEOTAIL,  16.384 Kbps - Record and Contingency (R/T)
0311, B, RT, GEOTAIL,  65.536 Kbps - Record and Contingency (R/T)
0307, C, PB, GEOTAIL,  65.536 Kbps - Record and Contingency (P/B)
0313, D, PB, GEOTAIL,  131.072 Kbps - Record and Contingency (R/T)
0312, Z, RT, SOHO, SOHO Real-time TLM (VC0 and VC1)
0324, Z, PB, SOHO, SOHO TR Dump TLM (VC4)
0327, Z, PB, SOHO, SOHO MDI TLM (VC2 and VC3)
E_O_T

for ( $I=0; $I<256 ; $I++ ) {   # initialize PDF to X and RTPB to XX and SAT to octal
        $PDF[ $I ] = $PDF_DESC[ $I ] =  "X" ;
        $PDF_RTPB[ $I ] = "XX" ;
        $PDF_SAT[ $I ] = sprintf( "0%3.3o", $I) ;
}

@PR = split( /\n/, $PDFT ) ;
$I = 0 ;
while( $PR[ $I ] ) {		# process each line of table information
    @LS=split( /\s*,\s*/, $PR[$I]); # split on commas and any surrounding whitespace
	$INDX 	  = oct( $LS[0] ) ;	# get numeric PDF code
	$PDF[ $INDX ]      = $LS[1] ;	# 1 char name
	$PDF_RTPB[ $INDX ] = $LS[2] ;	# Real-time or Playback (RT or PB)
	$PDF_SAT[ $INDX ]  = $LS[3] ; 	# Satellite name 
	$PDF_DESC[ $INDX ] = $LS[4] ;	# long description of PDF data
	$I++ ;
}

        #--------------------------------------------------
        #   Parse input parameters
        #--------------------------------------------------

if ( ! &Getopts( 'dfhv' ) ) { $opt_h=1; } # sets opt_* for each option

if ( $opt_d ) { $DEBUG++; }
if ( $opt_f ) { $FORCE++; }
if ( $opt_h ) { $HELP++; }
if ( $opt_v ) { $VERBOSE++; }

$NUMFILES = 0 ;
while ( $ARGV[0] ) {
	$FILENAME = $ARGV[0] ;
	shift;
	$NUMFILES++ ;
}

if ( $HELP || ($NUMFILES != 1) ) {
	split_usage() ;
	goto EXIT;
}

@FNIN = split( /\// , $FILENAME ) ;	# split file name on /
$I = @FNIN -1  ;			# get num of pieces,
$FILEONLY = $FNIN[ $I ] ; 		# grab field off end of file name
$FNIN[ $I ] = '' ;			# zap last field
$DIRONLY  = join( '/', @FNIN ) ;	# put whats left back together

$STARTTIME = time() ;

$RECNUM = 0 ;
$CONSEC_GOOD = 0 ;
$REC = "" ;
$PRTMSG = "" ;

$FLG = $DOY = $MSOD = $USOMS = 0 ;

$PREV_MSOD = $PREV_UOMS = 0 ;

$FN = '<'.$FILENAME ;
$XX = open( IN, $FN ) ;
if( $XX > 0 )
{
	if( $VERBOSE )
	{
		printf( STDERR "\nSCANNING DATA FILE...\n\n" ) ;
		printf( STDERR " Input Filename = %s\n", $FILENAME ) ;
	}
}
else
{
	# fatal error opening data file
	printf( STDERR "ERROR: lzp_split: open(%s)\n", $FILENAME ) ;
	goto EXIT;
}

$SAT = $RTPB = $PDF = $SRC = $DEST = $T1DOY = $T1MSOD = $T1USOMS = "" ;

$FILE_FMT = $REC_FMT = $BLK_TYPE = $FRM_TYPE = $DATA_TYPE = "" ;

$SYNCPAT = 0x0 ;

$F_HDR_LEN = $R_HDR_LEN = $R_DAT_LEN = $R_RS_LEN = $R_ANN_LEN = $R_TRL_LEN = 0 ;

$RB = sysread( IN, $REC, 720) ;
if( $RB != 720 ) {
	printf( STDERR "ERROR: lzp_split: unable to read 720 bytes\n" );
	goto PRINTSUMMARY;
}

if( Pattern_Loc( $REC, 0x627627, 0 ) ) {	# found Nascom block sync

	$SYNCPAT = 0x627627 ;
	
	$FILE_FMT = "GBRS" ;	
	$REC_FMT = "BLOCK" ;
	$BLK_TYPE = "DGIB" ;
	$DATA_TYPE = "TLM" ;	# set for basic telemetry for now
	$F_HDR_LEN = 0 ;
	$R_HDR_LEN = 0 ;
	$R_DAT_LEN = 600 ;
	
	if( Pattern_Loc( $REC, 0x627627, 600 ) ) { 	# back to back, no annotation
		$R_RS_LEN  = 0 ;
		$R_ANN_LEN = 0 ;
		$R_TRL_LEN = 0 ;
	}
	
	if( Pattern_Loc( $REC, 0x627627, 608 ) ) { 	# back to back, annotation
		$R_RS_LEN  = 0 ;
		$R_ANN_LEN = 8 ;
		$R_TRL_LEN = 0 ;
	}
}

if( Pattern_Loc( $REC, 0x627627, 116 ) ) { 	# IDR format

	$SYNCPAT = 0x627627 ;
	
	$FILE_FMT = "IDR" ;	
	$REC_FMT = "BLOCK" ;
	$BLK_TYPE = "DGIB" ;
	$DATA_TYPE = "TLM" ;	# set for basic telemetry for now
	$F_HDR_LEN = 96 ;
	$R_HDR_LEN = 20 ;
	$R_DAT_LEN = 600 ;
	$R_RS_LEN  = 0 ;
	$R_ANN_LEN = 0 ;
	$R_TRL_LEN = 4 ;
}

#
# now figure out Satellite and RTPB
#

if( $REC_FMT eq "BLOCK" ) {
	$REC_START = $F_HDR_LEN + $R_HDR_LEN ;

	$B = substr( $REC, $REC_START, $R_DAT_LEN ) ;

	( $XSRC, $XDST, $XSCID, $XDSID, $XTYPE ) = 
		unpack( "x3 C1 C1 x C1 C1 C1 x3", $B ) ;
	
	if( $BLK_TYPE eq "DGIB" ) {	# extract Ground receive time from block header
		@T1 = unpack( "x12 C6", $B ) ;
		$T1DOY = (( $T1[0] & 0x3f) << 3 ) | (( $T1[1] >> 5 ) & 0x7 )  ;
		$T1MSOD = (($T1[1] & 0x1f ) << 22) | ( $T1[2] << 14) | ( $T1[3] << 6 ) | (( $T1[4] >> 2 ) & 0x3f) ;
		$T1USOMS = ($T1[4] & 0x03 ) << 8 | $T1[5]  ;
	}

	if( $BLK_TYPE eq "DDPS" ) {
		$T1DOY = 0 ;
		$T1MSOD = 0 ;
		$T1USOMS = 0 ;
	}
}

if( not $FILE_FMT ) {		# if file type still not known, give up
	$FILE_FMT = "UNK" ;
	printf( STDERR "ERROR: lzp_split: unable to determine file type\n" );
	goto EXIT;
}

@STAT = stat( IN ) ;

$RTOT_LEN = $R_HDR_LEN + $R_DAT_LEN + $R_RS_LEN + $R_ANN_LEN + $R_TRL_LEN ;
$RBLK_STRT = $R_HDR_LEN ;

#########################################################################
#	Scan file and see if all blocks belong to a single data stream
#		based on the first 6 bytes after sync being identical
#		on all blocks
#
#	At this point the following are set
#
#	$REC = first record from file
#	$RB  = status from read into $REC (number of bytes read)
#	$RECLEN = length of records to read
#	$RTPB = "RT" or "PB" depending on data sequence
#
#
#######################################################################

$RS = seek( IN, 0, 0 ) ;	# rewind file

			# if file header, skip over it
if( $F_HDR_LEN ) { 
		$RH = sysread(   IN, $FILHDR, $F_HDR_LEN ) ; 
}

$RB = sysread( IN, $REC, $RTOT_LEN ) ;	# then get first record 
$RECNUM = 1 ;				# record numbers start at 1

$FIRST_HDR6 = substr( $REC, $RBLK_STRT+3, 6 ) ;	# grab 6 header bytes
$STR_HDR[ 0 ] = BLK_STR( $FIRST_HDR6 ) ;

while( $RB ) {

	$HDR6 = substr( $REC, $RBLK_STRT+3, 6 ) ;	# grab 6 header bytes
	
	if( $HDR6 ne $FIRST_HDR6 ) { goto SPLITFILE }	# if not match, go split file
	
	else { 
		$RB = sysread( IN, $REC, $RTOT_LEN ) ;	# then get next record 
		if( $RB > 0 and $RB != $RTOT_LEN ) {
			printf( STDERR "ERROR: lzp_split: record %d contains %d bytes\n",
				$RECNUM, $RB ) ;
			goto PRINTSUMMARY;
		}
		$RECNUM++ ;				# count records
	}
}

goto PRINTSUMMARY ;


#########################################################################
#	Scan file and generate separate files for each data stream
#
#######################################################################

SPLITFILE :

#rename ( $FILENAME[ $CURRFILE ], "ORIG.".$FILENAME[ $CURRFILE ] ) ;

$OFNUM = 0 ;
$RFILENAME[ $OFNUM ] = $DIRONLY . "$OFNUM." . $FILEONLY;	# Output file name (no >) for return
$OFILENAME[ $OFNUM ] = '>'. $RFILENAME[ $OFNUM ] ;	# Out filename with leading >
$OUTFD[ $OFNUM ] = "FD".$OFNUM ;

if( not $DEBUG ) {
	$YY = open( $OUTFD[ $OFNUM ], $OFILENAME[ $OFNUM ] ) ;
	if( $YY > 0 )
	{
		if( $VERBOSE )
		{
			printf( STDERR " Split Filename = %s\n", $RFILENAME[ $OFNUM ] ) ;
		}
	}
	else
	{
		# fatal error opening output file
		printf( STDERR "ERROR: lzp_split: open(%s)\n", $RFILENAME[ $OFNUM ] ) ;
		goto EXIT;
	}
}

$RS = seek( IN, 0, 0 ) ;	# rewind file
$RECNUM = 0;

if( $F_HDR_LEN ) { 	# if file header, copy it to output
	$RH = sysread(   IN, $FILHDR, $F_HDR_LEN ) ; 
	if( not $DEBUG ) {
		$WH = syswrite( $OUTFD[ $OFNUM ], $FILHDR, $F_HDR_LEN ) ; 
	}
}

$RB = sysread( IN, $REC, $RTOT_LEN ) ;	# then get first record 

$HDR6 = substr( $REC, $RBLK_STRT+3, 6 ) ;	# grab 6 header bytes
$STR_HDR[ $OFNUM ] = BLK_STR( $HDR6 ) ;
	
$HDR6_TBL{ $HDR6 } = $OFNUM;	# if match in header table, output to proper file

$D = 0 ;

while( $RB ) {

	$RECNUM++ ;				# record numbers start at 1
	$HDR6 = substr( $REC, $RBLK_STRT+3, 6 ) ;	# grab 6 header bytes
	
	if( defined $HDR6_TBL{ $HDR6 } ) {	# if match in header table, output to proper file
	
		#######################################################################
		#	if this blocks's stream already identified, just output
		#	that stream and count.  Else set up another stream.
		#######################################################################
		
		$OF = $HDR6_TBL{ $HDR6 } ;	# get index into tables for this stream
		
	}
		#######################################################################
		#	if this blocks's stream not identified.  Add this new header
		#	string to the table, open a new file, account for block and
		# 	let the normal output process write it out.
		#######################################################################
	
	else {			# if not defined, then must be new stream
	
		$OFNUM++;	# bump number of output files
	
		$HDR6_TBL{ $HDR6 } = $OFNUM ;
		$STR_HDR[ $OFNUM ] = BLK_STR( $HDR6 ) ;
		$OF = $HDR6_TBL{ $HDR6 } ;	# set index for this stream, 0=first stream
		
		$RFILENAME[ $OFNUM ] = $DIRONLY . "$OFNUM." . $FILEONLY;  # Output file name (no >) for return
		$OFILENAME[ $OFNUM ] = '>'. $RFILENAME[ $OFNUM ] ;	# Out filename with leading >
		$OUTFD[ $OFNUM ] = "FD".$OFNUM ;

		if( not $DEBUG ) {
			$YY = open( $OUTFD[ $OFNUM ], $OFILENAME[ $OFNUM ] ) ;
			if( $YY > 0 )
			{
				if( $VERBOSE )
				{
					printf( STDERR " Split Filename = %s\n", $RFILENAME[ $OFNUM ] ) ;
				}
			}
			else
			{
				# fatal error opening output file
				printf( STDERR "ERROR: lzp_split: open(%s)\n", $RFILENAME[ $OFNUM ] ) ;
				goto EXIT;
			}
		}

		$OF = $HDR6_TBL{ $HDR6 } ;	# set current output file descriptor
		
		if( $F_HDR_LEN and not $DEBUG ) { 	# if file header, copy it to output
			$WH = syswrite( $OUTFD[ $OF ], $FILHDR, $F_HDR_LEN ) ; # write file header
		}

	}

#########################################################################
#		At this point $OF points to the table entries for this
#		particular block stream.  Now just write out the header,
#		data and trailer parts of this record to the proper file.
#		Also, account for the number of blocks in each stream.
#
#######################################################################

				# copy block to output
	if( not $DEBUG ) {
		$WB = syswrite( $OUTFD[ $OF ], $REC, $RTOT_LEN ) ;
	}
		
	$OUTBLKS[ $OF ]++ ;	#count blocks out for each stream

	$RB = sysread( IN, $REC, $RTOT_LEN ) ;	# then get next record 
}

PRINTSUMMARY:

if( $VERBOSE )
{
	printf( STDERR "\nGENERATING DATA FILE REPORT...\n\n" ) ;
	printf( STDERR " Input Filename = %s\n", $FILENAME ) ;
	printf( STDERR "   Input Header = %s\n", $STR_HDR[ 0 ] ) ;
	printf( STDERR "   Input Blocks = %d\n", $RECNUM ) ;
}

if( $OFNUM == 0 )
{
	if( $VERBOSE )
	{
		printf( STDERR "Output Filename = %s\n", $FILENAME ) ;
		printf( STDERR "  Output Header = %s\n", $STR_HDR[ 0 ] ) ;
		printf( STDERR "  Output Blocks = %d\n", $RECNUM ) ;
	}
	printf( STDOUT "$FILENAME\n" ) ; # return name of input file
}
else
{
	for( $OUT=0; $OUT <= $OFNUM ; $OUT++ )
	{
		if( $VERBOSE )
		{
			printf( STDERR "Output Filename = %s\n", $RFILENAME[ $OUT ] ) ;
			printf( STDERR "  Output Header = %s\n", $STR_HDR[ $OUT ] ) ;
			printf( STDERR "  Output Blocks = %d\n", $OUTBLKS[ $OUT ] ) ;
		}
		$ORETURN = $ORETURN . $RFILENAME[ $OUT ] . " " ;
	}
	printf( STDOUT "$ORETURN\n" ) ; # return names of split files
	if( not $DEBUG and $FORCE ) { unlink( $FILENAME ) ; } # remove original file
}

#########################################################################
#	When done processing 
#	
#	Compute processing time and rate
#
#######################################################################

$STOPTIME = time() ;
$TOTTIME = $STOPTIME - $STARTTIME ;
if( $TOTTIME eq 0 ) { $TOTTIME = 1 }

$AVGRATE = $RECNUM  / $TOTTIME ;	# processing rate in frames/second
$AVGBITS = $AVGRATE * $RTOT_LEN * 8 ;	# processing rate in bits/second
$AVGKBPS = $AVGBITS / 1000 ;

if( $VERBOSE )
{
	printf( STDERR "\nGENERATING PERFORMANCE REPORT...\n\n" ) ;
	printf( STDERR "   Elapsed Time = %d seconds\n", $TOTTIME ) ;
	printf( STDERR "     Block Rate = %d block/sec\n", $AVGRATE ) ;
	printf( STDERR "       Bit Rate = %d kbit/sec\n", $AVGKBPS ) ;
}

EXIT:
		#######################
		# end of main program #
		#######################
exit ;


##################################################################################
##################################################################################
##################################################################################


#########################################################################
#       Subroutine to generate string based on Nascom block header passed in
#
#	$_[0] - $HDR6 string of first 6 header fields from a block
#
#	Returns - ASCII string
#
#########################################################################

#########################################################################
#
#       Nascom block header format (DGIB))
#
#      +--------+--------+ 
#    1 | Nascom 4800 BB  | 0 , 1	Nascom Sync ( first 16 bits)
#      +--------+--------+ 
#    2 | Sync   | Source | 2 , 3	Sync ( 8 )  ,  Source code
#      +--------+---+----+
#    3 | Dest   |Seq| BFC| 4 , 5	Destination ,  Seq(3)  BFC(5)
#      +--------+---+----+
#    4 | SCID   |  DSID  | 6 , 7	Spacecraft ID, Data Stream ID
#      +--------+--------+
#    5 | Type   | Blk Cnt| 8 , 9	Data Type   ,  Block count
#      +--------+--------+
#    6 |xyz  Blk Length  |10 ,11	Flgs(3)   Block len. bits (13)
#      +--------+--------+
#    7 |ab DOY(9) MSOD(5)|12 ,13	Flags(2)  DOY(9) First milliseconds of day (5)
#      +--------+--------+
#    8 |   MSOD ( 16 )   |14 ,15	  more milliseconds of day (16)
#      +--------+--------+
#    9 |MSOD(6) USOMS(10)|16 ,17	last MSOD(6)  Microseconds of millisecond (10)
#      +--------+--------+
#      |        |        |
#
#######################################################################

sub BLK_STR {

	@R = unpack( "C6", $_[0] ) ;	# unpack 6 bytes of header
	$BS_SRC = $SRC_ANT3[ $R[0] ] ;
	$BS_DST = $SRC_ANT3[ $R[1] ] ;
	$BS_BFC = sprintf( "%2.2x" , $R[2] ) ;
	@BS_SC = split( / /, $SCID[ $R[3] ]) ;
	$BS_SCID = $BS_SC[ 0 ] ;
	$BS_PDF = $PDF[ $R[4] ] ;
	$BS_TYP = sprintf( "%2.2x" , $R[5] ) ;

	$BS = sprintf( "%s %s %s %s %s %s", $BS_SRC, $BS_DST, $BS_BFC, $BS_SCID, $BS_PDF, $BS_TYP);
}

sub split_usage{ 
	printf ( STDERR "\nUSAGE:     lzp_split [-hvdf] file\n" ) ;
	printf ( STDERR "\nPURPOSE:   Demultiplexes input file by record header type\n" ) ;
	printf ( STDERR "\nOPTIONS:   -h     display help screen\n" ) ;
	printf ( STDERR   "           -v     enable verbose mode\n" ) ;
	printf ( STDERR   "           -d     debug without modifying\n" );
	printf ( STDERR   "           -f     force removal of original\n" );
	printf ( STDERR "\nSYNOPSIS:  The specified file is scanned for consistency\n" ) ;
	printf ( STDERR   "           and either left intact or demultiplexed into\n" ) ;
        printf ( STDERR   "           separate files by record header type.  A list\n" ) ;
	printf ( STDERR   "           of demultiplexed files is returned via STDOUT\n" ) ;
	printf ( STDERR   "           and the original file is removed.  Diagnostic\n" ) ;
	printf ( STDERR   "           messages appear on STDERR.\n" ) ;
	printf ( STDERR "\nNOTES:     The following example shows how to demultiplex\n" ) ;
	printf ( STDERR   "           and remove the file 094_47038135_000.GD3905I:\n" ) ;
	printf ( STDERR   "           lzp_split -v -f 094_47038135_000.GD3905I\n" ) ;
	printf ( STDERR "\n" ) ;
	exit( );
}


#
#	Pattern_Loc( $Record, $Pattern, $Loc )
#
#	Returns 0 = not found, 1 = found

sub Pattern_Loc{ 

local( $REC, $PAT, $LOC ) = @_ ;

$CHK_VAL = unpack( "x$LOC L1", $REC ) ;	# extract 4-byte string at offset

if( $PAT <= 0xffffff ) { $CHK_VAL = ( $CHK_VAL >> 8 ) & 0xffffff ; }	# shift for 3-byte string

if( $CHK_VAL == $PAT ) { return 1 }
	else { return 0 }
	
}


#sub BAD_HDR {
#@R = unpack( "C6", $_[0] );	# unpack 6 byte header
#$MISSION = split( ) ;
#if( $PDF[ $R[4] ] eq "X" ) return 1 ;
#if( $PDF_SAT[ $R[4] ] ne $MISSION ) return 2;
#
#return 0 ;
#}
