/*
* Copyright 2010, United States Geological Survey or
* third-party contributors as indicated by the @author tags.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package gov.usgs.anss.cd11;
import java.nio.ByteBuffer;
import java.util.GregorianCalendar;
/** This class does I/O and encodeing and decodeing of CD1.1 frames. It was implented
* using version 0.3 of the document dated 18 Dec 2002. References in here should be
* to that document. It can be use to load data for specific frame formats for output, but
* is mostly used for decoding incoming frames.
*
* @author davidketchum
*/
class CD11Frame {
private static final int TYPE_DATA=5;
private static final int TYPE_CD1_ENCAPSULATION=13;
private static final String [] typeString ={"zero","ConnRqst","ConnResp","OptRqst","OptResp",
"Data","Ack","Alert","CmdRqst","CmdResp","Ten","Eleven","Twelve","CD1Encap"};
// the header portion of the frame
private int type;
private int trailerOffset;
private byte [] creator;
private byte [] destination;
private long seq;
private int series; // The sequence series for the frame
// The trailer portion of the frame
private int authID; // Authentication identifier
private int authSize; // size of authentication body
private byte [] authBody; // the authorization body, if null, no authentication
private long commVerification; // This is essentially the CRC
private long commComputed; // This is the computed CRC from when the fram was read.
// the frame body
private byte [] body;
private int lenBody;
private ByteBuffer bbody;
private long outSeq; // Output Sequence number
private byte [] frameSet; // creator:destination padded to 20 character
//(used be getOutputBytes to know to do data frame processing)
// Data frame related fields
private int dataNChan;
private int dataFrameMS; // Data frame length in milliseconds
private String nominalTime; // The nominal time for all of the data
private StringBuilder channelString = new StringBuilder(100);
/** Return number of data channels in DataFrame
*
* @return # of channels
*/
public int getDataNchan() {return dataNChan;}
public int getDataFrameMS() {return dataFrameMS;}
public String getDataNominalTime() {return nominalTime;}
public StringBuilder getChannelString() {return channelString;}
private boolean crcOK() {return commVerification == commComputed;}
public int getType() {return type;}
public int getBodyLength() {return lenBody;}
public byte [] getBody() {return body;}
public ByteBuffer getBodyByteBuffer() {return bbody;}
public byte [] getAuthBody() {return authBody;}
public int getAuthSize() {return authSize;}
public int getAuthID() {return authID;}
public byte [] getCreator() {return creator;}
public byte [] getDestination() {return destination;}
public int getSeries() {return series;}
public long getSeq() {return seq;}
public long getOutSeq() {return outSeq;}
public String getCreatorString() {return stringFrom(creator, 8);}
public String getDestinationString() {return stringFrom(destination, 8);}
public String getFrameSetString() {return stringFrom(frameSet,20);}
/** CD1.1 uses null padded strings, but Java wants space padded for convenience. This routine
* will return a line from a byte array with zeros/null turned to spaces
* @param buf Buffer with data to convert to a string
* @param len Desired sring length
* @return A string with spaces replacing the nulls
*/
private static String stringFrom(byte [] buf, int len) {
for(int i=0; i<len; i++) if(buf[i] == 0) len = i;
return new String(buf, 0, len).trim();
}
public void setType(int ty) {type=ty;}
@Override
public String toString() {return "CD11Frm:"+(type >=0 && type <=13?typeString[type]:"UnkwnType")+
(type == TYPE_DATA || type == TYPE_CD1_ENCAPSULATION ? " "+nominalTime:"")+" toff="+trailerOffset+
" "+stringFrom(creator,8)+":"+stringFrom(destination,8)+" sq="+series+"/"+seq+
" bLen="+lenBody+" aid="+authID+" sz="+authSize+" CRC="+(crcOK()?"t":"f**");
}
/** given a 20 byte CD1.1 time string, convert it to a gregorian calendar
* @param s The 20 byte CD1.1 time string yyyyddd_hh:mm:ss.mmm
* @param g A gregorianCalendar to set to the time from s
*/
static void fromCDTimeString(String s, GregorianCalendar g) {
try {
int year = Integer.parseInt(s.substring(0,4));
int doy = Integer.parseInt(s.substring(4,7));
int hr = Integer.parseInt(s.substring(8,10));
int min = Integer.parseInt(s.substring(11,13));
int sec = Integer.parseInt(s.substring(14,16));
int ms = Integer.parseInt(s.substring(17,20));
int [] ymd = SeedUtil.ymd_from_doy(year, doy);
g.set(year, ymd[1]-1, ymd[2], hr, min, sec);
g.setTimeInMillis(g.getTimeInMillis()/1000L*1000L+ms);
}
catch(NumberFormatException e) {
g.setTimeInMillis(86400000L);
}
}
}