Java tutorial
/** * Copyright: 2007 Regents of the University of Hawaii and the * School of Ocean and Earth Science and Technology * Purpose: To convert a Seacat ASCII data source into RBNB Data Turbine * frames for archival and realtime access. * Authors: Christopher Jones * * $HeadURL$ * $LastChangedDate$ * $LastChangedBy$ * $LastChangedRevision$ * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package edu.hawaii.soest.kilonalu.ctd; import edu.hawaii.soest.kilonalu.ctd.CTDConverter; import edu.hawaii.soest.kilonalu.ctd.CTDParser; import com.rbnb.sapi.ChannelMap; import com.rbnb.sapi.Source; import com.rbnb.sapi.SAPIException; import java.lang.StringBuffer; import java.io.PrintWriter; import java.io.InputStream; import java.io.OutputStream; import java.io.DataInputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.TimeZone; import java.util.zip.Inflater; import java.util.zip.DataFormatException; import org.apache.commons.cli.Options; import org.apache.commons.cli.CommandLine; import org.apache.commons.codec.binary.Hex; import org.apache.commons.math.linear.Array2DRowRealMatrix; import org.apache.commons.math.linear.ArrayRealVector; import org.apache.commons.math.linear.RealMatrix; import org.apache.log4j.Logger; import org.apache.log4j.BasicConfigurator; import org.apache.log4j.PropertyConfigurator; import org.nees.rbnb.RBNBBase; import org.nees.rbnb.RBNBSource; /** * A simple class used to harvest a compressed hexadecimal ASCII data file * from a Brooke Ocean Seahorse profiler equipped with a Seacat SBE19plus CTD. * Communication is over a TCP socket connection with an Iridium satellite modem * and a serial2ip converter host. The data samples are then converted into RBNB * frames and pushed into the RBNB DataTurbine real time server. This class * extends org.nees.rbnb.RBNBSource, which in turn extends org.nees.rbnb.RBNBBase, * and therefore follows the API conventions found in the org.nees.rbnb code. * * The parsing of the data stream relies on the premise that each sample (scan) * of data is a Hex-encoded string of values, and that each sample is terminated * by a newline character (\n). It is also assumed that the sample rate is 4Hz, * or a sample is taken every 15 seconds. * */ public class SeahorseSource extends RBNBSource { /* * A default archive mode for the given source connection to the RBNB server. * Valid modes include 'append', 'create', 'load' and 'none'. */ private final String DEFAULT_ARCHIVE_MODE = "append"; /* * The mode in which the source interacts with the RBNB archive. Valid modes * include 'append', 'create', 'load' and 'none', however, Kilo Nalu * instruments should append to an archive, which will create one if none * exist. * * @see setArchiveMode() * @see getArchiveMode() */ private String archiveMode = DEFAULT_ARCHIVE_MODE; /* * The default size of the ByteBuffer used to beffer the TCP stream from the * source instrument. */ private int DEFAULT_BUFFER_SIZE = 8096; // 8K /** * The size of the ByteBuffer used to beffer the TCP stream from the * instrument. */ private int bufferSize = DEFAULT_BUFFER_SIZE; /* A default RBNB channel name for the given source instrument */ private String DEFAULT_RBNB_CHANNEL = "HexadecimalASCIISampleData"; /** The name of the RBNB channel for this data stream */ private String rbnbChannelName = DEFAULT_RBNB_CHANNEL; /* A default source IP address for the given source instrument */ private final String DEFAULT_SOURCE_HOST_NAME = "127.0.0.1"; /** * The domain name or IP address of the host machine that this Source * represents and from which the data will stream. */ private String sourceHostName = DEFAULT_SOURCE_HOST_NAME; /* A default source TCP port for the given source instrument */ private final int DEFAULT_SOURCE_HOST_PORT = 2101; /** The TCP port to connect to on the Source host machine */ private int sourceHostPort = DEFAULT_SOURCE_HOST_PORT; /* The socket channel used to establish TCP communication with the instrument */ private SocketChannel socketChannel; /** The number of bytes in the ensemble as each byte is read from the stream */ private int resultByteCount = 0; /** The command prefix used to send commands to the microcontroller */ private String MODEM_COMMAND_PREFIX = "AT"; /** The command suffix used to send commands to the microcontroller */ private final String MODEM_COMMAND_SUFFIX = "\r"; /** The command used to get the network registration status from the Iridium modem */ private final String REGISTRATION_STATUS_COMMAND = "+CREG?"; /** The command used to get the signal strength from the Iridium modem */ private final String SIGNAL_STRENGTH_COMMAND = "+CSQ"; /** The command used to answer a RING call from the Iridium modem */ private final String ANSWER_COMMAND = "A"; /** The command used to acknowledge the connection from the instrument */ private final String ACKNOWLEDGE_COMMAND = "ACK"; /** The command used to get the ID from the instrument */ private final String ID_COMMAND = "GID"; /** The platform ID of the instrument (i.e. the SeahHorse identifier, not the CTD) */ private String platformID = ""; /** The command used to get the battery voltage from the instrument */ private final String BATTERY_VOLTAGE_COMMAND = "GBV"; /** The command used to get the GPRMC data string from the instrument */ private final String GPRMC_COMMAND = "GPS"; /** The command used to get the name of the file to be downloaded from the instrument */ private final String FILENAME_COMMAND = "GFN"; /** The command used to get the remaining number of blocks (bytes) from the instrument */ private final String NUMBER_OF_BLOCKS_COMMAND = "GNB"; /** The remaining number of blocks (bytes) to download from the instrument */ private int numberOfBlocks = 0; /** The command used to transfer blocks (bytes) from the instrument */ private final String TRANSFER_BLOCKS_COMMAND = "TXB"; /** The command used to disconnect (hang up) with the Iridium modem */ private final String HANGUP_COMMAND = "H0"; /** The command used to close the transfer session with the instrument */ private final String CLOSE_TRANSFER_SESSION_COMMAND = "REL"; /** The command used to escape to command mode with the Iridium modem */ private final String ESCAPE_SEQUENCE_COMMAND = "+++"; /** The okay status string expected from the instrument */ private final String OKAY_STATUS = "OK"; /** The signal strength string expected from Iridium modem */ private final String SIGNAL_STRENGTH = "+CSQ:"; /** The signal strength threshold string needed from Iridium modem (0 - 5) */ private final int SIGNAL_THRESHOLD = 3; /** The registration status string expected from the instrument */ private final String REGISTRATION_STATUS = "+CREG:"; /** The call ring string expected from the instrument */ private final String CALL_RING = "RING"; /** The connect rate string expected from the instrument */ private final String CONNECT_RATE = "CONNECT 19200"; /** The ready status string expected from the instrument */ private final String READY_STATUS = "READY"; /** The file name prefix string expected from the instrument */ private final String FILENAME_PREFIX = "FILE="; /** The file name to be downloaded from the instrument */ private String fileNameToDownload = ""; /** The prefix string expected at the beginning of the data file name */ private final String DATA_FILE_PREFIX = "SH__"; /** The prefix string expected at the beginning of the cast file name */ private final String CAST_FILE_PREFIX = "CAST"; /** The blocksize prefix string expected from the instrument */ private final String BLOCKSIZE_PREFIX = "BLOCKSIZE="; /** The transfer complete string expected from the instrument */ private final String TRANSFER_COMPLETE = "DONE"; /** The end of files string expected from the instrument */ private final String END_OF_FILES = "NONE"; /** The session closed string expected from the instrument */ private final String SESSION_CLOSED = "BYE"; /** The data file string downloaded from the instrument */ private String dataFileString = ""; /** The cast file string downloaded from the instrument */ private String castFileString = ""; /** The command sent to the instrument */ private String command; /* A boolean field indicating if a command has been sent to the instrument */ private boolean sentCommand = false; /* * The instance of the CTDParser object used to parse the CTD * data file and retrieve each of the data fields */ private CTDParser ctdParser = null; /** The default log configuration file location */ private final String DEFAULT_LOG_CONFIGURATION_FILE = "lib/log4j.properties"; /** The log configuration file location */ private String logConfigurationFile = DEFAULT_LOG_CONFIGURATION_FILE; /** The Logger instance used to log system messages */ private static Logger logger = Logger.getLogger(SeahorseSource.class); /* The channel map object used to transfer data to the DataTurbine*/ private ChannelMap rbnbChannelMap; /* The channel index integer used to populate the channel map */ int channelIndex; protected int state = 0; private boolean readyToStream = false; private Thread streamingThread; /* * An internal Thread setting used to specify how long, in milliseconds, the * execution of the data streaming Thread should wait before re-executing * * @see execute() */ private final int RETRY_INTERVAL = 5000; /* * An internal Thread setting used to specify how long, in milliseconds, the * execution of the data streaming Thread should sleep before continuing * * @see execute() */ private final int SLEEP_INTERVAL = 5000; /** * The date format for the timestamp applied to the CTD sample e.g. "23 Sep 2009 11:29:15" */ private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd MMM yyyy HH:mm:ss"); /** The timezone used for the sample date */ private static final TimeZone TZ = TimeZone.getTimeZone("HST"); /* The sample datetime reported by the parsed CTD data file as a Calendar */ private Calendar sampleDateTime; /** * Constructor - create an empty instance of the SeahorseSource object, using * default values for the RBNB server name and port, source instrument name * and port, archive mode, archive frame size, and cache frame size. */ public SeahorseSource() { } /** * Constructor - create an instance of the SeahorseSource object, using the * argument values for the source instrument name and port, and the RBNB * server name and port. This constructor will use default values for the * archive mode, archive frame size, and cache frame size. * * @param sourceHostName the name or IP address of the source instrument * @param sourceHostPort the TCP port of the source host instrument * @param serverName the name or IP address of the RBNB server connection * @param serverPort the TCP port of the RBNB server */ public SeahorseSource(String sourceHostName, String sourceHostPort, String serverName, String serverPort) { setHostName(sourceHostName); setHostPort(Integer.parseInt(sourceHostPort)); setServerName(serverName); setServerPort(Integer.parseInt(serverPort)); } /** * Constructor - create an instance of the SeahorseSource object, using the * argument values for the source instrument name and port, and the RBNB * server name and port, the archive mode, archive frame size, and cache * frame size. A frame is created at each call to flush() to an RBNB server, * and so the frame sizes below are relative to the number of bytes of data * loaded in the ChannelMap that is flushed to the RBNB server. * * @param sourceHostName the name or IP address of the source instrument * @param sourceHostPort the TCP port of the source host instrument * @param serverName the name or IP address of the RBNB server * @param serverPort the TCP port of the RBNB server * @param archiveMode the RBNB archive mode: append, load, create, none * @param archiveFrameSize the size, in frames, for the RBNB server to archive * @param cacheFrameSize the size, in frames, for the RBNB server to cache * @param rbnbClientName the unique name of the source RBNB client */ public SeahorseSource(String sourceHostName, String sourceHostPort, String serverName, String serverPort, String archiveMode, int archiveFrameSize, int cacheFrameSize, String rbnbClientName) { setHostName(sourceHostName); setHostPort(Integer.parseInt(sourceHostPort)); setServerName(serverName); setServerPort(Integer.parseInt(serverPort)); setArchiveMode(archiveMode); setArchiveSize(archiveFrameSize); setCacheSize(cacheFrameSize); setRBNBClientName(rbnbClientName); } /** * A method that executes the streaming of data from the source to the RBNB * server after all configuration of settings, connections to hosts, and * thread initiatizing occurs. This method contains the detailed code for * streaming the data and interpreting the stream. */ protected boolean execute() { logger.debug("SeahorseSource.execute() called."); // do not execute the stream if there is no connection if (!isConnected()) return false; boolean failed = false; this.socketChannel = getSocketConnection(); // while data are being sent, read them into the buffer try { // create four byte placeholders used to evaluate up to a four-byte // window. The FIFO layout looks like: // ------------------------- // in ---> | One | Two |Three|Four | ---> out // ------------------------- byte byteOne = 0x00, // set initial placeholder values byteTwo = 0x00, byteThree = 0x00, byteFour = 0x00; // define a byte array that will be used to manipulate the incoming bytes byte[] resultArray; String resultString; // Create a buffer that will store the result bytes as they are read ByteBuffer resultBuffer = ByteBuffer.allocate(getBufferSize()); // create a byte buffer to store bytes from the TCP stream ByteBuffer buffer = ByteBuffer.allocateDirect(getBufferSize()); this.rbnbChannelMap = new ChannelMap(); this.channelIndex = 0; // initiate the session with the modem, test if is network registered this.command = this.MODEM_COMMAND_PREFIX + this.REGISTRATION_STATUS_COMMAND + this.MODEM_COMMAND_SUFFIX; this.sentCommand = queryInstrument(this.command); // allow time for the modem to respond streamingThread.sleep(this.SLEEP_INTERVAL); // while there are bytes to read from the socketChannel ... while (socketChannel.read(buffer) != -1 || buffer.position() > 0) { // prepare the buffer for reading buffer.flip(); // while there are unread bytes in the ByteBuffer while (buffer.hasRemaining()) { byteOne = buffer.get(); //logger.debug("b1: " + new String(Hex.encodeHex((new byte[]{byteOne}))) + "\t" + // "b2: " + new String(Hex.encodeHex((new byte[]{byteTwo}))) + "\t" + // "b3: " + new String(Hex.encodeHex((new byte[]{byteThree}))) + "\t" + // "b4: " + new String(Hex.encodeHex((new byte[]{byteFour}))) + "\t" + // "result pos: " + resultBuffer.position() + "\t" + // "result rem: " + resultBuffer.remaining() + "\t" + // "result cnt: " + resultByteCount + "\t" + // "buffer pos: " + buffer.position() + "\t" + // "buffer rem: " + buffer.remaining() + "\t" + // "state: " + state //); // Use a State Machine to process the byte stream. // Start building an rbnb frame for the entire sample, first by // inserting a timestamp into the channelMap. This time is merely // the time of insert into the data turbine, not the time of // observations of the measurements. That time should be parsed out // of the sample in the Sink client code switch (state) { case 0: // the network registration status should end in OK\r\n // note bytes are in reverse order in the FIFO window if (byteOne == 0x0A && byteTwo == 0x0D && byteThree == 0x4B && byteFour == 0x4F) { logger.debug("Received the registration status result."); this.resultByteCount++; // add the last byte found to the count // add the last byte found to the result buffer if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); resultBuffer.put(byteOne); } // report the network registration status string resultArray = new byte[this.resultByteCount]; resultBuffer.flip(); resultBuffer.get(resultArray); resultString = new String(resultArray, "US-ASCII"); logger.debug("Network Registration Result: " + resultString.trim()); resultBuffer.clear(); this.resultByteCount = 0; resultArray = new byte[0]; resultString = ""; byteOne = 0x00; byteTwo = 0x00; byteThree = 0x00; byteFour = 0x00; // send a request for the signal strength this.command = this.MODEM_COMMAND_PREFIX + this.SIGNAL_STRENGTH_COMMAND + this.MODEM_COMMAND_SUFFIX; this.sentCommand = queryInstrument(this.command); // allow time for the modem to respond streamingThread.sleep(this.SLEEP_INTERVAL); state = 1; break; } else { this.resultByteCount++; // add the last byte found to the count // add the last byte found to the result buffer if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); resultBuffer.put(byteOne); } break; } case 1: // report the signal strength of the Iridium modem // the signal strength status should end in OK\r\n // note bytes are in reverse order in the FIFO window if (byteOne == 0x0A && byteTwo == 0x0D && byteThree == 0x4B && byteFour == 0x4F) { logger.debug("Received the signal strength result."); this.resultByteCount++; // add the last byte found to the count // add the last byte found to the result buffer if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); resultBuffer.put(byteOne); } // report the signal strength status string resultArray = new byte[this.resultByteCount]; resultBuffer.flip(); resultBuffer.get(resultArray); resultString = new String(resultArray, "US-ASCII"); logger.debug("Signal Strength Result: " + resultString.trim()); int signalStrengthIndex = resultString.indexOf(this.SIGNAL_STRENGTH) + 5; int signalStrength = new Integer( resultString.substring(signalStrengthIndex, signalStrengthIndex + 1)) .intValue(); // test if the signal strength is above the threshold if (signalStrength > SIGNAL_THRESHOLD) { resultBuffer.clear(); this.resultByteCount = 0; resultArray = new byte[0]; resultString = ""; byteOne = 0x00; byteTwo = 0x00; byteThree = 0x00; byteFour = 0x00; state = 2; break; // the signal strength is too low, check again } else { resultBuffer.clear(); this.resultByteCount = 0; resultArray = new byte[0]; resultString = ""; byteOne = 0x00; byteTwo = 0x00; byteThree = 0x00; byteFour = 0x00; // resend a request for the signal strength this.command = this.MODEM_COMMAND_PREFIX + this.SIGNAL_STRENGTH_COMMAND + this.MODEM_COMMAND_SUFFIX; this.sentCommand = queryInstrument(this.command); // allow time for the modem to respond streamingThread.sleep(this.SLEEP_INTERVAL); state = 1; break; } } else { // still in the middle of the result, keep adding bytes this.resultByteCount++; // add each byte found if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); logger.debug("Compacting resultBuffer ..."); resultBuffer.put(byteOne); } break; } case 2: // handle the RING command from the instrument // listen for the RING command // note bytes are in reverse order in the FIFO window if (byteOne == 0x47 && byteTwo == 0x4E && byteThree == 0x49 && byteFour == 0x52) { logger.debug("Received the RING command."); this.resultByteCount++; // add the last byte found to the count // add the last byte found to the result buffer if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); resultBuffer.put(byteOne); } resultBuffer.clear(); this.resultByteCount = 0; resultArray = new byte[0]; resultString = ""; byteOne = 0x00; byteTwo = 0x00; byteThree = 0x00; byteFour = 0x00; // answer the call this.command = this.MODEM_COMMAND_PREFIX + this.ANSWER_COMMAND + this.MODEM_COMMAND_SUFFIX; this.sentCommand = queryInstrument(this.command); // allow time for the modem to respond streamingThread.sleep(this.SLEEP_INTERVAL); state = 3; break; } else { // still in the middle of the result, keep adding bytes this.resultByteCount++; // add each byte found if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); logger.debug("Compacting resultBuffer ..."); resultBuffer.put(byteOne); } break; } case 3: // acknowledge the connection // the ready status string should end in READY\r // note bytes are in reverse order in the FIFO window if (byteOne == 0x0D && byteTwo == 0x59 && byteThree == 0x44 && byteFour == 0x41) { logger.debug("Received the ready status result."); this.resultByteCount++; // add the last byte found to the count // add the last byte found to the result buffer if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); resultBuffer.put(byteOne); } // report the connect rate and ready status string resultArray = new byte[this.resultByteCount]; resultBuffer.flip(); resultBuffer.get(resultArray); resultString = new String(resultArray, "US-ASCII"); // test the connect rate logger.debug("Result from ATA: " + resultString); if (resultString.indexOf(this.CONNECT_RATE) > 0) { logger.debug("Connect Rate Result: " + this.CONNECT_RATE); // test the ready status if (resultString.indexOf(this.READY_STATUS) > 0) { logger.debug("Connect Rate Result: " + this.READY_STATUS); resultBuffer.clear(); this.resultByteCount = 0; resultArray = new byte[0]; resultString = ""; byteOne = 0x00; byteTwo = 0x00; byteThree = 0x00; byteFour = 0x00; // acknowledge the ready status this.command = this.ACKNOWLEDGE_COMMAND + this.MODEM_COMMAND_SUFFIX; this.sentCommand = queryInstrument(this.command); // allow time for the modem to receive the ACK streamingThread.sleep(this.SLEEP_INTERVAL); // query the instrument id this.command = this.ID_COMMAND + this.MODEM_COMMAND_SUFFIX; this.sentCommand = queryInstrument(this.command); // allow time for the modem to respond streamingThread.sleep(this.SLEEP_INTERVAL); state = 4; break; } else { logger.debug("The ready status differs from: " + this.READY_STATUS); // throw an exception here? break; } } else { logger.debug("The connect rate differs from: " + this.CONNECT_RATE); // throw an exception here? break; } } else { // still in the middle of the result, keep adding bytes this.resultByteCount++; // add each byte found if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); logger.debug("Compacting resultBuffer ..."); resultBuffer.put(byteOne); } break; } case 4: // get the instrument id // the instrument ID string should end in \r if (byteOne == 0x0D) { logger.debug("Received the instrument ID result."); this.resultByteCount++; // add the last byte found to the count // add the last byte found to the result buffer if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); resultBuffer.put(byteOne); } // report the instrument ID string resultArray = new byte[this.resultByteCount]; resultBuffer.flip(); resultBuffer.get(resultArray); resultString = new String(resultArray, "US-ASCII"); logger.debug("Seahorse Instrument ID: " + resultString.trim()); // set the platformID variable this.platformID = resultString.substring(0, resultString.length() - 1); resultBuffer.clear(); this.resultByteCount = 0; resultArray = new byte[0]; resultString = ""; byteOne = 0x00; byteTwo = 0x00; byteThree = 0x00; byteFour = 0x00; // query the battery voltage this.command = this.BATTERY_VOLTAGE_COMMAND + this.MODEM_COMMAND_SUFFIX; this.sentCommand = queryInstrument(this.command); // allow time for the modem to respond streamingThread.sleep(this.SLEEP_INTERVAL); state = 5; break; } else { // still in the middle of the result, keep adding bytes this.resultByteCount++; // add each byte found if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); logger.debug("Compacting resultBuffer ..."); resultBuffer.put(byteOne); } break; } case 5: // get the seahorse battery voltage // the battery voltage string should end in \r if (byteOne == 0x0D) { logger.debug("Received the instrument battery voltage result."); this.resultByteCount++; // add the last byte found to the count // add the last byte found to the result buffer if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); resultBuffer.put(byteOne); } // report the battery voltage string resultArray = new byte[this.resultByteCount]; resultBuffer.flip(); resultBuffer.get(resultArray); resultString = new String(resultArray, "US-ASCII"); logger.debug("Seahorse Battery Voltage: " + resultString.trim()); resultBuffer.clear(); this.resultByteCount = 0; resultArray = new byte[0]; resultString = ""; byteOne = 0x00; byteTwo = 0x00; byteThree = 0x00; byteFour = 0x00; // query the GPS location this.command = this.GPRMC_COMMAND + this.MODEM_COMMAND_SUFFIX; this.sentCommand = queryInstrument(this.command); // allow time for the modem to respond streamingThread.sleep(this.SLEEP_INTERVAL); state = 6; break; } else { // still in the middle of the result, keep adding bytes this.resultByteCount++; // add each byte found if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); logger.debug("Compacting resultBuffer ..."); resultBuffer.put(byteOne); } break; } case 6: // the GPRMC string should end in END\r // note bytes are in reverse order in the FIFO window if (byteOne == 0x0D && byteTwo == 0x44 && byteThree == 0x4E && byteFour == 0x45) { logger.debug("Received the GPRMS result."); this.resultByteCount++; // add the last byte found to the count // add the last byte found to the result buffer if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); resultBuffer.put(byteOne); } // report the GPRMC string resultArray = new byte[this.resultByteCount]; resultBuffer.flip(); resultBuffer.get(resultArray); resultString = new String(resultArray, "US-ASCII"); logger.debug("Seahorse GPRMC string: " + resultString.trim()); resultBuffer.clear(); this.resultByteCount = 0; resultArray = new byte[0]; resultString = ""; byteOne = 0x00; byteTwo = 0x00; byteThree = 0x00; byteFour = 0x00; // query the file name for transfer this.command = this.FILENAME_COMMAND + this.MODEM_COMMAND_SUFFIX; this.sentCommand = queryInstrument(this.command); // allow time for the modem to respond streamingThread.sleep(this.SLEEP_INTERVAL); state = 7; break; } else { // still in the middle of the result, keep adding bytes this.resultByteCount++; // add each byte found if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); logger.debug("Compacting resultBuffer ..."); resultBuffer.put(byteOne); } break; } case 7: // the file name string should end in .Z\r // note bytes are in reverse order in the FIFO window if (byteOne == 0x0D && byteTwo == 0x5A && byteThree == 0x2E) { logger.debug("Received the file name result."); this.resultByteCount++; // add the last byte found to the count // add the last byte found to the result buffer if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); resultBuffer.put(byteOne); } // report the file name string resultArray = new byte[this.resultByteCount]; resultBuffer.flip(); resultBuffer.get(resultArray); resultString = new String(resultArray, "US-ASCII"); logger.debug("File name result: " + resultString.trim()); resultString = resultString.trim(); int fileNameIndex = resultString.indexOf(this.FILENAME_PREFIX); //extract just the filename from the result (excise the "FILE=") this.fileNameToDownload = resultString.substring( (fileNameIndex + (this.FILENAME_PREFIX).length()), resultString.length()); logger.debug("File name to download: " + this.fileNameToDownload); // test to see if the GFN command returns FILES=NONE if (!(resultString.indexOf(this.END_OF_FILES) > 0)) { // there is a file to download. parse the file name, // get the number of blocks to transfer this.command = this.NUMBER_OF_BLOCKS_COMMAND + this.MODEM_COMMAND_SUFFIX; this.sentCommand = queryInstrument(this.command); // allow time for the modem to respond streamingThread.sleep(this.SLEEP_INTERVAL); resultBuffer.clear(); this.resultByteCount = 0; resultArray = new byte[0]; resultString = ""; byteOne = 0x00; byteTwo = 0x00; byteThree = 0x00; byteFour = 0x00; state = 8; break; } else { // We have downloaded all files. Parse the data string, // build the channel map, and flush the data to the Dataturbine // by iterating through the data matrix. The metadata and // ASCII data strings are flushed once with the first matrix // row. // Parse the data file, not the cast file. try { // parse the CTD data file this.ctdParser = new CTDParser(this.dataFileString); // convert the raw frequencies and voltages to engineering // units and return the data as a matrix CTDConverter ctdConverter = new CTDConverter(this.ctdParser); ctdConverter.convert(); RealMatrix convertedDataMatrix = ctdConverter.getConvertedDataValuesMatrix(); // Register the data and metadata channels; failed = register(); if (!failed) { // format the first sample date and use it as the first insert // date. Add the sampleInterval on each iteration to insert // subsequent data rows. Sample interval is by default // 4 scans/second for the CTD. DATE_FORMAT.setTimeZone(TZ); this.sampleDateTime = Calendar.getInstance(); this.sampleDateTime .setTime(DATE_FORMAT.parse(ctdParser.getFirstSampleTime())); for (int row = 0; row < convertedDataMatrix.getRowDimension(); row++) { // Only insert the metadata fields and full ASCII text strings // with the first row of data if (row == 0) { // Add the samplingMode data to the channel map this.channelIndex = this.rbnbChannelMap.Add("samplingMode"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getSamplingMode()); // Add the firstSampleTime data to the channel map this.channelIndex = this.rbnbChannelMap.Add("firstSampleTime"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getFirstSampleTime()); // Add the fileName data to the channel map this.channelIndex = this.rbnbChannelMap.Add("fileName"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getFileName()); // Add the temperatureSerialNumber data to the channel map this.channelIndex = this.rbnbChannelMap .Add("temperatureSerialNumber"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getTemperatureSerialNumber()); // Add the conductivitySerialNumber data to the channel map this.channelIndex = this.rbnbChannelMap .Add("conductivitySerialNumber"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getConductivitySerialNumber()); // Add the systemUpLoadTime data to the channel map this.channelIndex = this.rbnbChannelMap.Add("systemUpLoadTime"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getSystemUpLoadTime()); // Add the cruiseInformation data to the channel map this.channelIndex = this.rbnbChannelMap.Add("cruiseInformation"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getCruiseInformation()); // Add the stationInformation data to the channel map this.channelIndex = this.rbnbChannelMap.Add("stationInformation"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getStationInformation()); // Add the shipInformation data to the channel map this.channelIndex = this.rbnbChannelMap.Add("shipInformation"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getShipInformation()); // Add the chiefScientist data to the channel map this.channelIndex = this.rbnbChannelMap.Add("chiefScientist"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getChiefScientist()); // Add the organization data to the channel map this.channelIndex = this.rbnbChannelMap.Add("organization"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getOrganization()); // Add the areaOfOperation data to the channel map this.channelIndex = this.rbnbChannelMap.Add("areaOfOperation"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getAreaOfOperation()); // Add the instrumentPackage data to the channel map this.channelIndex = this.rbnbChannelMap.Add("instrumentPackage"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getInstrumentPackage()); // Add the mooringNumber data to the channel map this.channelIndex = this.rbnbChannelMap.Add("mooringNumber"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getMooringNumber()); // Add the instrumentLatitude data to the channel map this.channelIndex = this.rbnbChannelMap.Add("instrumentLatitude"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getInstrumentLatitude() }); // Add the instrumentLongitude data to the channel map this.channelIndex = this.rbnbChannelMap.Add("instrumentLongitude"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getInstrumentLongitude() }); // Add the depthSounding data to the channel map this.channelIndex = this.rbnbChannelMap.Add("depthSounding"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getDepthSounding() }); // Add the profileNumber data to the channel map this.channelIndex = this.rbnbChannelMap.Add("profileNumber"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getProfileNumber()); // Add the profileDirection data to the channel map this.channelIndex = this.rbnbChannelMap.Add("profileDirection"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getProfileDirection()); // Add the deploymentNotes data to the channel map this.channelIndex = this.rbnbChannelMap.Add("deploymentNotes"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getDeploymentNotes()); // Add the mainBatteryVoltage data to the channel map this.channelIndex = this.rbnbChannelMap.Add("mainBatteryVoltage"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getMainBatteryVoltage() }); // Add the lithiumBatteryVoltage data to the channel map this.channelIndex = this.rbnbChannelMap .Add("lithiumBatteryVoltage"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getLithiumBatteryVoltage() }); // Add the operatingCurrent data to the channel map this.channelIndex = this.rbnbChannelMap.Add("operatingCurrent"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getOperatingCurrent() }); // Add the pumpCurrent data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pumpCurrent"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getPumpCurrent() }); // Add the channels01ExternalCurrent data to the channel map this.channelIndex = this.rbnbChannelMap .Add("channels01ExternalCurrent"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getChannels01ExternalCurrent() }); // Add the channels23ExternalCurrent data to the channel map this.channelIndex = this.rbnbChannelMap .Add("channels23ExternalCurrent"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getChannels23ExternalCurrent() }); // Add the loggingStatus data to the channel map this.channelIndex = this.rbnbChannelMap.Add("loggingStatus"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getLoggingStatus()); // Add the numberOfScansToAverage data to the channel map this.channelIndex = this.rbnbChannelMap .Add("numberOfScansToAverage"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsInt32(this.channelIndex, new int[] { this.ctdParser.getNumberOfScansToAverage() }); // Add the numberOfSamples data to the channel map this.channelIndex = this.rbnbChannelMap.Add("numberOfSamples"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsInt32(this.channelIndex, new int[] { this.ctdParser.getNumberOfSamples() }); // Add the numberOfAvailableSamples data to the channel map this.channelIndex = this.rbnbChannelMap .Add("numberOfAvailableSamples"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsInt32(this.channelIndex, new int[] { this.ctdParser.getNumberOfAvailableSamples() }); // Add the sampleInterval data to the channel map this.channelIndex = this.rbnbChannelMap.Add("sampleInterval"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsInt32(this.channelIndex, new int[] { this.ctdParser.getSampleInterval() }); // Add the measurementsPerSample data to the channel map this.channelIndex = this.rbnbChannelMap .Add("measurementsPerSample"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsInt32(this.channelIndex, new int[] { this.ctdParser.getMeasurementsPerSample() }); // Add the transmitRealtime data to the channel map this.channelIndex = this.rbnbChannelMap.Add("transmitRealtime"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getTransmitRealtime()); // Add the numberOfCasts data to the channel map this.channelIndex = this.rbnbChannelMap.Add("numberOfCasts"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsInt32(this.channelIndex, new int[] { this.ctdParser.getNumberOfCasts() }); // Add the minimumConductivityFrequency data to the channel map this.channelIndex = this.rbnbChannelMap .Add("minimumConductivityFrequency"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsInt32(this.channelIndex, new int[] { this.ctdParser.getMinimumConductivityFrequency() }); // Add the pumpDelay data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pumpDelay"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsInt32(this.channelIndex, new int[] { this.ctdParser.getPumpDelay() }); // Add the automaticLogging data to the channel map this.channelIndex = this.rbnbChannelMap.Add("automaticLogging"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getAutomaticLogging()); // Add the ignoreMagneticSwitch data to the channel map this.channelIndex = this.rbnbChannelMap.Add("ignoreMagneticSwitch"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getIgnoreMagneticSwitch()); // Add the batteryType data to the channel map this.channelIndex = this.rbnbChannelMap.Add("batteryType"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getBatteryType()); // Add the batteryCutoff data to the channel map this.channelIndex = this.rbnbChannelMap.Add("batteryCutoff"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getBatteryCutoff()); // Add the pressureSensorType data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureSensorType"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getPressureSensorType()); // Add the pressureSensorRange data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureSensorRange"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getPressureSensorRange()); // Add the sbe38TemperatureSensor data to the channel map this.channelIndex = this.rbnbChannelMap .Add("sbe38TemperatureSensor"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getSbe38TemperatureSensor()); // Add the gasTensionDevice data to the channel map this.channelIndex = this.rbnbChannelMap.Add("gasTensionDevice"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getGasTensionDevice()); // Add the externalVoltageChannelZero data to the channel map this.channelIndex = this.rbnbChannelMap .Add("externalVoltageChannelZero"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getExternalVoltageChannelZero()); // Add the externalVoltageChannelOne data to the channel map this.channelIndex = this.rbnbChannelMap .Add("externalVoltageChannelOne"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getExternalVoltageChannelOne()); // Add the externalVoltageChannelTwo data to the channel map this.channelIndex = this.rbnbChannelMap .Add("externalVoltageChannelTwo"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getExternalVoltageChannelTwo()); // Add the externalVoltageChannelThree data to the channel map this.channelIndex = this.rbnbChannelMap .Add("externalVoltageChannelThree"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getExternalVoltageChannelThree()); // Add the echoCommands data to the channel map this.channelIndex = this.rbnbChannelMap.Add("echoCommands"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getEchoCommands()); // Add the outputFormat data to the channel map this.channelIndex = this.rbnbChannelMap.Add("outputFormat"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getOutputFormat()); // Add the temperatureCalibrationDate data to the channel map this.channelIndex = this.rbnbChannelMap .Add("temperatureCalibrationDate"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getTemperatureCalibrationDate()); // Add the temperatureCoefficientTA0 data to the channel map this.channelIndex = this.rbnbChannelMap .Add("temperatureCoefficientTA0"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getTemperatureCoefficientTA0() }); // Add the temperatureCoefficientTA1 data to the channel map this.channelIndex = this.rbnbChannelMap .Add("temperatureCoefficientTA1"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getTemperatureCoefficientTA1() }); // Add the temperatureCoefficientTA2 data to the channel map this.channelIndex = this.rbnbChannelMap .Add("temperatureCoefficientTA2"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getTemperatureCoefficientTA2() }); // Add the temperatureCoefficientTA3 data to the channel map this.channelIndex = this.rbnbChannelMap .Add("temperatureCoefficientTA3"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getTemperatureCoefficientTA3() }); // Add the temperatureOffsetCoefficient data to the channel map this.channelIndex = this.rbnbChannelMap .Add("temperatureOffsetCoefficient"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getTemperatureOffsetCoefficient() }); // Add the conductivityCalibrationDate data to the channel map this.channelIndex = this.rbnbChannelMap .Add("conductivityCalibrationDate"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getConductivityCalibrationDate()); // Add the conductivityCoefficientG data to the channel map this.channelIndex = this.rbnbChannelMap .Add("conductivityCoefficientG"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getConductivityCoefficientG() }); // Add the conductivityCoefficientH data to the channel map this.channelIndex = this.rbnbChannelMap .Add("conductivityCoefficientH"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getConductivityCoefficientH() }); // Add the conductivityCoefficientI data to the channel map this.channelIndex = this.rbnbChannelMap .Add("conductivityCoefficientI"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getConductivityCoefficientI() }); // Add the conductivityCoefficientJ data to the channel map this.channelIndex = this.rbnbChannelMap .Add("conductivityCoefficientJ"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getConductivityCoefficientJ() }); // Add the conductivityCoefficientCF0 data to the channel map this.channelIndex = this.rbnbChannelMap .Add("conductivityCoefficientCF0"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getConductivityCoefficientCF0() }); // Add the conductivityCoefficientCPCOR data to the channel map this.channelIndex = this.rbnbChannelMap .Add("conductivityCoefficientCPCOR"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getConductivityCoefficientCPCOR() }); // Add the conductivityCoefficientCTCOR data to the channel map this.channelIndex = this.rbnbChannelMap .Add("conductivityCoefficientCTCOR"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getConductivityCoefficientCTCOR() }); // Add the conductivityCoefficientCSLOPE data to the channel map this.channelIndex = this.rbnbChannelMap .Add("conductivityCoefficientCSLOPE"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser .getConductivityCoefficientCSLOPE() }); // Add the pressureSerialNumber data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureSerialNumber"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.ctdParser.getPressureSerialNumber()); // Add the pressureCoefficientPA0 data to the channel map this.channelIndex = this.rbnbChannelMap .Add("pressureCoefficientPA0"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getPressureCoefficientPA0() }); // Add the pressureCoefficientPA1 data to the channel map this.channelIndex = this.rbnbChannelMap .Add("pressureCoefficientPA1"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getPressureCoefficientPA1() }); // Add the pressureCoefficientPA2 data to the channel map this.channelIndex = this.rbnbChannelMap .Add("pressureCoefficientPA2"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getPressureCoefficientPA2() }); // Add the pressureCoefficientPTCA0 data to the channel map this.channelIndex = this.rbnbChannelMap .Add("pressureCoefficientPTCA0"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getPressureCoefficientPTCA0() }); // Add the pressureCoefficientPTCA1 data to the channel map this.channelIndex = this.rbnbChannelMap .Add("pressureCoefficientPTCA1"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getPressureCoefficientPTCA1() }); // Add the pressureCoefficientPTCA2 data to the channel map this.channelIndex = this.rbnbChannelMap .Add("pressureCoefficientPTCA2"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getPressureCoefficientPTCA2() }); // Add the pressureCoefficientPTCB0 data to the channel map this.channelIndex = this.rbnbChannelMap .Add("pressureCoefficientPTCB0"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getPressureCoefficientPTCB0() }); // Add the pressureCoefficientPTCB1 data to the channel map this.channelIndex = this.rbnbChannelMap .Add("pressureCoefficientPTCB1"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getPressureCoefficientPTCB1() }); // Add the pressureCoefficientPTCB2 data to the channel map this.channelIndex = this.rbnbChannelMap .Add("pressureCoefficientPTCB2"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getPressureCoefficientPTCB2() }); // Add the pressureCoefficientPTEMPA0 data to the channel map this.channelIndex = this.rbnbChannelMap .Add("pressureCoefficientPTEMPA0"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getPressureCoefficientPTEMPA0() }); // Add the pressureCoefficientPTEMPA1 data to the channel map this.channelIndex = this.rbnbChannelMap .Add("pressureCoefficientPTEMPA1"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getPressureCoefficientPTEMPA1() }); // Add the pressureCoefficientPTEMPA2 data to the channel map this.channelIndex = this.rbnbChannelMap .Add("pressureCoefficientPTEMPA2"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getPressureCoefficientPTEMPA2() }); // Add the pressureOffsetCoefficient data to the channel map this.channelIndex = this.rbnbChannelMap .Add("pressureOffsetCoefficient"); this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { this.ctdParser.getPressureOffsetCoefficient() }); // Insert the file into the channel map. this.channelIndex = this.rbnbChannelMap.Add(this.rbnbChannelName); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.dataFileString); this.channelIndex = this.rbnbChannelMap.Add("ASCIICastData"); this.rbnbChannelMap.PutMime(this.channelIndex, "text/plain"); this.rbnbChannelMap.PutDataAsString(this.channelIndex, this.castFileString); } // Add in the matrix data row to the map here List<String> variableNames = ctdParser.getDataVariableNames(); List<String> variableUnits = ctdParser.getDataVariableUnits(); // iterate through the variable names and add them to // the channel map. for (int variableIndex = 0; variableIndex < variableNames .size(); variableIndex++) { // Add the variable name to the channel map this.channelIndex = this.rbnbChannelMap .Add(variableNames.get(variableIndex)); // The matrix is a double array, so set the data type below this.rbnbChannelMap.PutMime(this.channelIndex, "application/octet-stream"); // add the data to the map from the [row,column] of the // matrix (row is from the outer for loop) this.rbnbChannelMap.PutDataAsFloat64(this.channelIndex, new double[] { convertedDataMatrix.getEntry(row, variableIndex) }); } // Flush the channel map to the RBNB double sampleTimeAsSecondsSinceEpoch = (double) (this.sampleDateTime .getTimeInMillis() / 1000); this.rbnbChannelMap.PutTime(sampleTimeAsSecondsSinceEpoch, 0d); getSource().Flush(this.rbnbChannelMap); logger.info("Flushed data to the DataTurbine."); this.rbnbChannelMap.Clear(); // samples are taken 4x per second, so increment the // sample time by 250 milliseconds for the next insert this.sampleDateTime.add(Calendar.MILLISECOND, 250); } // end for loop } // end if !failed } catch (Exception e) { logger.debug("Failed to parse the CTD data file: " + e.getMessage()); } // there are no more files to read. close the Tx session. this.command = this.CLOSE_TRANSFER_SESSION_COMMAND + this.MODEM_COMMAND_SUFFIX; this.sentCommand = queryInstrument(this.command); // allow time for the modem to respond streamingThread.sleep(this.SLEEP_INTERVAL); // clean up resultBuffer.clear(); this.resultByteCount = 0; resultArray = new byte[0]; resultString = ""; byteOne = 0x00; byteTwo = 0x00; byteThree = 0x00; byteFour = 0x00; state = 10; break; } } else { // still in the middle of the result, keep adding bytes this.resultByteCount++; // add each byte found if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); logger.debug("Compacting resultBuffer ..."); resultBuffer.put(byteOne); } break; } case 8: // the number of blocks string should end in \r if (byteOne == 0x0D) { logger.debug("Received the number of blocks result."); this.resultByteCount++; // add the last byte found to the count // add the last byte found to the result buffer if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); resultBuffer.put(byteOne); } // report the number of blocks string resultArray = new byte[this.resultByteCount]; resultBuffer.flip(); resultBuffer.get(resultArray); resultString = new String(resultArray, "US-ASCII"); logger.debug("Number of bytes reported: " + resultString.trim()); int numberOfBlocksIndex = resultString.indexOf(this.BLOCKSIZE_PREFIX); // If 'BLOCKSIZE=' is not found, set the index to 0 if (numberOfBlocksIndex == -1) { numberOfBlocksIndex = 0; } resultString = resultString.substring( (numberOfBlocksIndex + (this.BLOCKSIZE_PREFIX).length()), resultString.length()); // convert the string to an integer try { this.numberOfBlocks = new Integer(resultString.trim()).intValue(); logger.debug("Number of bytes to download: " + this.numberOfBlocks); } catch (java.lang.NumberFormatException nfe) { failed = true; nfe.printStackTrace(); logger.debug("Failed to convert returned string value " + "to an integer value. The returned string is: " + this.numberOfBlocks); } // test to see if the GNB command returns DONE\r if (!(resultString.indexOf(this.TRANSFER_COMPLETE) > 0)) { // there are bytes to transfer. send the transfer command this.command = this.TRANSFER_BLOCKS_COMMAND + this.MODEM_COMMAND_SUFFIX; this.sentCommand = queryInstrument(this.command); // allow time for the modem to respond streamingThread.sleep(this.SLEEP_INTERVAL); //resultBuffer.clear(); dont clear the buffer this.resultByteCount = 0; resultArray = new byte[0]; resultString = ""; byteOne = 0x00; byteTwo = 0x00; byteThree = 0x00; byteFour = 0x00; state = 9; break; } else { // there are no more bytes to transfer. // Decompress the file, which is under zlib compression. Inflater inflater = new Inflater(); inflater.setInput(resultBuffer.array()); byte[] output = new byte[resultBuffer.capacity()]; int numDecompressed = inflater.inflate(output); // set the appropriate string variable if (this.fileNameToDownload.indexOf(DATA_FILE_PREFIX) > 0) { this.dataFileString = new String(output); //report the file contents to the log logger.debug("File " + this.fileNameToDownload + ": "); logger.debug(this.dataFileString); } else { this.castFileString = new String(output); //report the file contents to the log logger.debug("File " + this.fileNameToDownload + ": "); logger.debug(this.castFileString); } // Ask for the next file. this.command = this.FILENAME_COMMAND + this.MODEM_COMMAND_SUFFIX; this.sentCommand = queryInstrument(this.command); // allow time for the modem to respond streamingThread.sleep(this.SLEEP_INTERVAL); //resultBuffer.clear(); dont clear the buffer this.resultByteCount = 0; resultArray = new byte[0]; resultString = ""; byteOne = 0x00; byteTwo = 0x00; byteThree = 0x00; byteFour = 0x00; state = 7; //back to the file name state break; } } else { // still in the middle of the result, keep adding bytes this.resultByteCount++; // add each byte found if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); logger.debug("Compacting resultBuffer ..."); resultBuffer.put(byteOne); } break; } case 9: // transfer up to the reported number of bytes if (this.resultByteCount == this.numberOfBlocks) { // we have downloaded the reported bytes. get the next section. // get the number of blocks to transfer this.command = this.NUMBER_OF_BLOCKS_COMMAND + this.MODEM_COMMAND_SUFFIX; this.sentCommand = queryInstrument(this.command); // allow time for the modem to respond streamingThread.sleep(this.SLEEP_INTERVAL); //resultBuffer.clear(); this.resultByteCount = 0; byteOne = 0x00; byteTwo = 0x00; byteThree = 0x00; byteFour = 0x00; state = 8; break; } else { // still in the middle of the result, keep adding bytes this.resultByteCount++; // add each byte found if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); logger.debug("Compacting resultBuffer ..."); resultBuffer.put(byteOne); } break; } case 10: // the response from the modem should end in BYE\r // note bytes are in reverse order in the FIFO window if (byteOne == 0x0D && byteTwo == 0x45 && byteThree == 0x59 && byteFour == 0x42) { logger.debug("Received the BYE command."); // continue to disconnect. send the escape sequence this.command = this.ESCAPE_SEQUENCE_COMMAND + this.MODEM_COMMAND_SUFFIX; this.sentCommand = queryInstrument(this.command); // allow time for the modem to respond streamingThread.sleep(this.SLEEP_INTERVAL); resultBuffer.clear(); this.resultByteCount = 0; byteOne = 0x00; byteTwo = 0x00; byteThree = 0x00; byteFour = 0x00; state = 11; break; } else { // still in the middle of the result, keep adding bytes this.resultByteCount++; // add each byte found if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); logger.debug("Compacting resultBuffer ..."); resultBuffer.put(byteOne); } break; } case 11: // the response from the modem should end in OK\r\n // note bytes are in reverse order in the FIFO window if (byteOne == 0x0D && byteTwo == 0x0A && byteThree == 0x4B && byteFour == 0x4F) { // now hang up. this.command = this.MODEM_COMMAND_PREFIX + this.HANGUP_COMMAND + this.MODEM_COMMAND_SUFFIX; this.sentCommand = queryInstrument(this.command); // allow time for the modem to respond streamingThread.sleep(this.SLEEP_INTERVAL); resultBuffer.clear(); this.resultByteCount = 0; byteOne = 0x00; byteTwo = 0x00; byteThree = 0x00; byteFour = 0x00; state = 12; break; } else { // still in the middle of the result, keep adding bytes this.resultByteCount++; // add each byte found if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); logger.debug("Compacting resultBuffer ..."); resultBuffer.put(byteOne); } break; } case 12: // the response from the modem should end in OK\r\n // note bytes are in reverse order in the FIFO window if (byteOne == 0x0D && byteTwo == 0x0A && byteThree == 0x4B && byteFour == 0x4F) { // we are done. re-test if is network registered this.command = this.MODEM_COMMAND_PREFIX + this.REGISTRATION_STATUS_COMMAND + this.MODEM_COMMAND_SUFFIX; this.sentCommand = queryInstrument(this.command); // allow time for the modem to respond streamingThread.sleep(this.SLEEP_INTERVAL); resultBuffer.clear(); this.resultByteCount = 0; byteOne = 0x00; byteTwo = 0x00; byteThree = 0x00; byteFour = 0x00; state = 0; break; } else { // still in the middle of the result, keep adding bytes this.resultByteCount++; // add each byte found if (resultBuffer.remaining() > 0) { resultBuffer.put(byteOne); } else { resultBuffer.compact(); logger.debug("Compacting resultBuffer ..."); resultBuffer.put(byteOne); } break; } } // end switch statement // shift the bytes in the FIFO window byteFour = byteThree; byteThree = byteTwo; byteTwo = byteOne; } //end while (more unread bytes) // prepare the buffer to read in more bytes from the stream buffer.compact(); } // end while (more socketChannel bytes to read) socketChannel.close(); } catch (IOException e) { // handle exceptions // In the event of an i/o exception, log the exception, and allow execute() // to return false, which will prompt a retry. failed = true; e.printStackTrace(); return !failed; } catch (java.lang.InterruptedException ine) { failed = true; ine.printStackTrace(); return !failed; } catch (java.util.zip.DataFormatException dfe) { failed = true; dfe.printStackTrace(); return !failed; } return !failed; } // end if ( !isConnected() ) /** * A method used to the TCP socket of the remote source host for communication * @param host the name or IP address of the host to connect to for the * socket connection (reading) * @param portNumber the number of the TCP port to connect to (i.e. 2604) */ protected SocketChannel getSocketConnection() { String host = getHostName(); int portNumber = new Integer(getHostPort()).intValue(); SocketChannel dataSocket = null; try { // create the socket channel connection to the data source via the // converter serial2IP converter dataSocket = SocketChannel.open(); dataSocket.connect(new InetSocketAddress(host, portNumber)); // if the connection to the source fails, also disconnect from the RBNB // server and return null if (!dataSocket.isConnected()) { dataSocket.close(); disconnect(); dataSocket = null; } } catch (UnknownHostException ukhe) { System.err.println("Unable to look up host: " + host + "\n"); disconnect(); dataSocket = null; } catch (IOException nioe) { System.err.println("Couldn't get I/O connection to: " + host); disconnect(); dataSocket = null; } catch (Exception e) { disconnect(); dataSocket = null; } return dataSocket; } /** * A method that sets the size, in bytes, of the ByteBuffer used in streaming * data from a source instrument via a TCP connection */ public int getBufferSize() { return this.bufferSize; } /** * A method that returns the domain name or IP address of the source * instrument (i.e. the serial-to-IP converter to which it is attached) */ public String getHostName() { return this.sourceHostName; } /** * A method that returns the name of the RBNB channel that contains the * streaming data from this instrument */ public String getRBNBChannelName() { return this.rbnbChannelName; } /** A method that queries the instrument with a command */ public boolean queryInstrument(String command) { // the result of the query boolean result = false; // only send the command if the socket is connected if (this.socketChannel.isConnected()) { ByteBuffer commandBuffer = ByteBuffer.allocate(command.length() * 10); commandBuffer.put(command.getBytes()); commandBuffer.flip(); try { this.socketChannel.write(commandBuffer); logger.debug("Wrote " + command + " to the socket channel."); result = true; } catch (IOException ioe) { ioe.printStackTrace(); result = false; } } return result; } /** * A method that returns the TCP port of the source * instrument (i.e. the serial-to-IP converter to which it is attached) */ public int getHostPort() { return this.sourceHostPort; } /** * A method that returns the versioning info for this file. In this case, * it returns a String that includes the Subversion LastChangedDate, * LastChangedBy, LastChangedRevision, and HeadURL fields. */ public String getCVSVersionString() { return ("$LastChangedDate$" + "$LastChangedBy$" + "$LastChangedRevision$" + "$HeadURL$"); } /** * A method that returns true if the RBNB connection is established * and if the data streaming Thread has been started */ public boolean isRunning() { // return the connection status and the thread status return (isConnected() && readyToStream); } /** * The main method for running the code * @ param args[] the command line list of string arguments, none are needed */ public static void main(String args[]) { logger.info("SeahorseSource.main() called."); try { // create a new instance of the SeahorseSource object, and parse the command // line arguments as settings for this instance final SeahorseSource seahorseSource = new SeahorseSource(); // Set up a simple logger that logs to the console PropertyConfigurator.configure(seahorseSource.getLogConfigurationFile()); // parse the commandline arguments to configure the connection, then // start the streaming connection between the source and the RBNB server. if (seahorseSource.parseArgs(args)) { seahorseSource.start(); } // Handle ctrl-c's and other abrupt death signals to the process Runtime.getRuntime().addShutdownHook(new Thread() { // stop the streaming process public void run() { seahorseSource.stop(); } }); } catch (Exception e) { logger.info("Error in main(): " + e.getMessage()); e.printStackTrace(); } } /* * A method that registers the CTD data and metadata channels with the * DataTurbine. * * return boolean - returns true if the registration result succeeds */ private boolean register() { // Register the CTD data and metadata channels with the DataTurbine try { // Add the sample data channel as ASCII Hex this.channelIndex = this.rbnbChannelMap.Add(this.rbnbChannelName); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the cast data as ASCII this.channelIndex = this.rbnbChannelMap.Add("ASCIICastData"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the samplingMode data to the channel map this.channelIndex = this.rbnbChannelMap.Add("samplingMode"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the firstSampleTime data to the channel map this.channelIndex = this.rbnbChannelMap.Add("firstSampleTime"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the fileName data to the channel map this.channelIndex = this.rbnbChannelMap.Add("fileName"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the temperatureSerialNumber data to the channel map this.channelIndex = this.rbnbChannelMap.Add("temperatureSerialNumber"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the conductivitySerialNumber data to the channel map this.channelIndex = this.rbnbChannelMap.Add("conductivitySerialNumber"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the systemUpLoadTime data to the channel map this.channelIndex = this.rbnbChannelMap.Add("systemUpLoadTime"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the cruiseInformation data to the channel map this.channelIndex = this.rbnbChannelMap.Add("cruiseInformation"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the stationInformation data to the channel map this.channelIndex = this.rbnbChannelMap.Add("stationInformation"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the shipInformation data to the channel map this.channelIndex = this.rbnbChannelMap.Add("shipInformation"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the chiefScientist data to the channel map this.channelIndex = this.rbnbChannelMap.Add("chiefScientist"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the organization data to the channel map this.channelIndex = this.rbnbChannelMap.Add("organization"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the areaOfOperation data to the channel map this.channelIndex = this.rbnbChannelMap.Add("areaOfOperation"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the instrumentPackage data to the channel map this.channelIndex = this.rbnbChannelMap.Add("instrumentPackage"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the mooringNumber data to the channel map this.channelIndex = this.rbnbChannelMap.Add("mooringNumber"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the instrumentLatitude data to the channel map this.channelIndex = this.rbnbChannelMap.Add("instrumentLatitude"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=degrees"); // Add the instrumentLongitude data to the channel map this.channelIndex = this.rbnbChannelMap.Add("instrumentLongitude"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=degrees"); // Add the depthSounding data to the channel map this.channelIndex = this.rbnbChannelMap.Add("depthSounding"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=m"); // Add the profileNumber data to the channel map this.channelIndex = this.rbnbChannelMap.Add("profileNumber"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the profileDirection data to the channel map this.channelIndex = this.rbnbChannelMap.Add("profileDirection"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the deploymentNotes data to the channel map this.channelIndex = this.rbnbChannelMap.Add("deploymentNotes"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the mainBatteryVoltage data to the channel map this.channelIndex = this.rbnbChannelMap.Add("mainBatteryVoltage"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=v"); // Add the lithiumBatteryVoltage data to the channel map this.channelIndex = this.rbnbChannelMap.Add("lithiumBatteryVoltage"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=v"); // Add the operatingCurrent data to the channel map this.channelIndex = this.rbnbChannelMap.Add("operatingCurrent"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=ma"); // Add the pumpCurrent data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pumpCurrent"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=ma"); // Add the channels01ExternalCurrent data to the channel map this.channelIndex = this.rbnbChannelMap.Add("channels01ExternalCurrent"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=ma"); // Add the channels23ExternalCurrent data to the channel map this.channelIndex = this.rbnbChannelMap.Add("channels23ExternalCurrent"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=ma"); // Add the loggingStatus data to the channel map this.channelIndex = this.rbnbChannelMap.Add("loggingStatus"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the numberOfScansToAverage data to the channel map this.channelIndex = this.rbnbChannelMap.Add("numberOfScansToAverage"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the numberOfSamples data to the channel map this.channelIndex = this.rbnbChannelMap.Add("numberOfSamples"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the numberOfAvailableSamples data to the channel map this.channelIndex = this.rbnbChannelMap.Add("numberOfAvailableSamples"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the sampleInterval data to the channel map this.channelIndex = this.rbnbChannelMap.Add("sampleInterval"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the measurementsPerSample data to the channel map this.channelIndex = this.rbnbChannelMap.Add("measurementsPerSample"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the transmitRealtime data to the channel map this.channelIndex = this.rbnbChannelMap.Add("transmitRealtime"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the numberOfCasts data to the channel map this.channelIndex = this.rbnbChannelMap.Add("numberOfCasts"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the minimumConductivityFrequency data to the channel map this.channelIndex = this.rbnbChannelMap.Add("minimumConductivityFrequency"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=Hz"); // Add the pumpDelay data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pumpDelay"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=s"); // Add the automaticLogging data to the channel map this.channelIndex = this.rbnbChannelMap.Add("automaticLogging"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the ignoreMagneticSwitch data to the channel map this.channelIndex = this.rbnbChannelMap.Add("ignoreMagneticSwitch"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the batteryType data to the channel map this.channelIndex = this.rbnbChannelMap.Add("batteryType"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the batteryCutoff data to the channel map this.channelIndex = this.rbnbChannelMap.Add("batteryCutoff"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the pressureSensorType data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureSensorType"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the pressureSensorRange data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureSensorRange"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the sbe38TemperatureSensor data to the channel map this.channelIndex = this.rbnbChannelMap.Add("sbe38TemperatureSensor"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the gasTensionDevice data to the channel map this.channelIndex = this.rbnbChannelMap.Add("gasTensionDevice"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the externalVoltageChannelZero data to the channel map this.channelIndex = this.rbnbChannelMap.Add("externalVoltageChannelZero"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the externalVoltageChannelOne data to the channel map this.channelIndex = this.rbnbChannelMap.Add("externalVoltageChannelOne"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the externalVoltageChannelTwo data to the channel map this.channelIndex = this.rbnbChannelMap.Add("externalVoltageChannelTwo"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the externalVoltageChannelThree data to the channel map this.channelIndex = this.rbnbChannelMap.Add("externalVoltageChannelThree"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the echoCommands data to the channel map this.channelIndex = this.rbnbChannelMap.Add("echoCommands"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the outputFormat data to the channel map this.channelIndex = this.rbnbChannelMap.Add("outputFormat"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the temperatureCalibrationDate data to the channel map this.channelIndex = this.rbnbChannelMap.Add("temperatureCalibrationDate"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the temperatureCoefficientTA0 data to the channel map this.channelIndex = this.rbnbChannelMap.Add("temperatureCoefficientTA0"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the temperatureCoefficientTA1 data to the channel map this.channelIndex = this.rbnbChannelMap.Add("temperatureCoefficientTA1"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the temperatureCoefficientTA2 data to the channel map this.channelIndex = this.rbnbChannelMap.Add("temperatureCoefficientTA2"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the temperatureCoefficientTA3 data to the channel map this.channelIndex = this.rbnbChannelMap.Add("temperatureCoefficientTA3"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the temperatureOffsetCoefficient data to the channel map this.channelIndex = this.rbnbChannelMap.Add("temperatureOffsetCoefficient"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the conductivityCalibrationDate data to the channel map this.channelIndex = this.rbnbChannelMap.Add("conductivityCalibrationDate"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the conductivityCoefficientG data to the channel map this.channelIndex = this.rbnbChannelMap.Add("conductivityCoefficientG"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the conductivityCoefficientH data to the channel map this.channelIndex = this.rbnbChannelMap.Add("conductivityCoefficientH"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the conductivityCoefficientI data to the channel map this.channelIndex = this.rbnbChannelMap.Add("conductivityCoefficientI"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the conductivityCoefficientJ data to the channel map this.channelIndex = this.rbnbChannelMap.Add("conductivityCoefficientJ"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the conductivityCoefficientCF0 data to the channel map this.channelIndex = this.rbnbChannelMap.Add("conductivityCoefficientCF0"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the conductivityCoefficientCPCOR data to the channel map this.channelIndex = this.rbnbChannelMap.Add("conductivityCoefficientCPCOR"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the conductivityCoefficientCTCOR data to the channel map this.channelIndex = this.rbnbChannelMap.Add("conductivityCoefficientCTCOR"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the conductivityCoefficientCSLOPE data to the channel map this.channelIndex = this.rbnbChannelMap.Add("conductivityCoefficientCSLOPE"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the pressureSerialNumber data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureSerialNumber"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the pressureCoefficientPA0 data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureCoefficientPA0"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the pressureCoefficientPA1 data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureCoefficientPA1"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the pressureCoefficientPA2 data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureCoefficientPA2"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the pressureCoefficientPTCA0 data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureCoefficientPTCA0"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the pressureCoefficientPTCA1 data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureCoefficientPTCA1"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the pressureCoefficientPTCA2 data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureCoefficientPTCA2"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the pressureCoefficientPTCB0 data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureCoefficientPTCB0"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the pressureCoefficientPTCB1 data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureCoefficientPTCB1"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the pressureCoefficientPTCB2 data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureCoefficientPTCB2"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the pressureCoefficientPTEMPA0 data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureCoefficientPTEMPA0"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the pressureCoefficientPTEMPA1 data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureCoefficientPTEMPA1"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the pressureCoefficientPTEMPA2 data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureCoefficientPTEMPA2"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); // Add the pressureOffsetCoefficient data to the channel map this.channelIndex = this.rbnbChannelMap.Add("pressureOffsetCoefficient"); this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=none"); List<String> unitNames = this.ctdParser.getDataVariableUnits(); // iterate through the variable units and add them to the channel map. for (int unitIndex = 0; unitIndex < unitNames.size(); unitIndex++) { // Add the unit name to the channel map this.channelIndex = this.rbnbChannelMap.Add(unitNames.get(unitIndex)); // The matrix is a double array, so set the data type below this.rbnbChannelMap.PutUserInfo(this.channelIndex, "units=" + unitNames.get(unitIndex)); } // register the channel map of variables and units with the DataTurbine getSource().Register(this.rbnbChannelMap); // reset variables for use with the incoming data this.rbnbChannelMap.Clear(); this.channelIndex = 0; return true; } catch (SAPIException sapie) { // In the event of an RBNB communication exception, log the exception, // and allow execute() to return false, which will prompt a retry. logger.debug("There was a problem registering the channels." + " The error message was: " + sapie.getMessage()); sapie.printStackTrace(); return false; } } /* * A method that runs the data streaming work performed by the execute() * by handling execution problems and continuously trying to re-execute after * a specified retry interval for the thread. */ private void runWork() { // handle execution problems by retrying if execute() fails boolean retry = true; while (retry) { // connect to the RBNB server if (connect()) { // run the data streaming code retry = !execute(); } disconnect(); if (retry) { try { Thread.sleep(RETRY_INTERVAL); } catch (Exception e) { logger.info("There was an execution problem. Retrying. Message is: " + e.getMessage()); } } } // stop the streaming when we are done stop(); } /** * A method that sets the command line arguments for this class. This method * calls the <code>RBNBSource.setBaseArgs()</code> method. * * @param command The CommandLine object being passed in from the command */ protected boolean setArgs(CommandLine command) { // first set the base arguments that are included on the command line if (!setBaseArgs(command)) { return false; } // add command line arguments here // handle the -H option if (command.hasOption("H")) { String hostName = command.getOptionValue("H"); if (hostName != null) { setHostName(hostName); } } // handle the -P option, test if it's an integer if (command.hasOption("P")) { String hostPort = command.getOptionValue("P"); if (hostPort != null) { try { setHostPort(Integer.parseInt(hostPort)); } catch (NumberFormatException nfe) { logger.info("Error: Enter a numeric value for the host port. " + hostPort + " is not a valid number."); return false; } } } // handle the -C option if (command.hasOption("C")) { String channelName = command.getOptionValue("C"); if (channelName != null) { setChannelName(channelName); } } return true; } /** * A method that sets the size, in bytes, of the ByteBuffer used in streaming * data from a source instrument via a TCP connection * * @param bufferSize the size, in bytes, of the ByteBuffer */ public void setBuffersize(int bufferSize) { this.bufferSize = bufferSize; } /** * A method that sets the RBNB channel name of the source instrument's data * stream * * @param channelName the name of the RBNB channel being streamed */ public void setChannelName(String channelName) { this.rbnbChannelName = channelName; } /** * A method that sets the domain name or IP address of the source * instrument (i.e. the serial-to-IP converter to which it is attached) * * @param hostName the domain name or IP address of the source instrument */ public void setHostName(String hostName) { this.sourceHostName = hostName; } /** * A method that sets the TCP port of the source * instrument (i.e. the serial-to-IP converter to which it is attached) * * @param hostPort the TCP port of the source instrument */ public void setHostPort(int hostPort) { this.sourceHostPort = hostPort; } /** * A method that sets the command line options for this class. This method * calls the <code>RBNBSource.setBaseOptions()</code> method in order to set * properties such as the sourceHostName, sourceHostPort, serverName, and * serverPort. */ protected Options setOptions() { Options options = setBaseOptions(new Options()); // Note: // Command line options already provided by RBNBBase include: // -h "Print help" // -s "RBNB Server Hostname" // -p "RBNB Server Port Number" // -S "RBNB Source Name" // -v "Print Version information" // Command line options already provided by RBNBSource include: // -z "Cache size" // -Z "Archive size" // add command line options here options.addOption("H", true, "Source host name or IP *" + getHostName()); options.addOption("P", true, "Source host port number *" + getHostPort()); options.addOption("C", true, "RBNB source channel name *" + getRBNBChannelName()); //options.addOption("M", true, "RBNB archive mode *" + getArchiveMode()); return options; } /** * A method that starts the streaming of data from the source instrument to * the RBNB server via an established TCP connection. */ public boolean start() { // return false if the streaming is running if (isRunning()) { return false; } // reset the connection to the RBNB server if (isConnected()) { disconnect(); } connect(); // return false if the connection fails if (!isConnected()) { return false; } // begin the streaming thread to the source startThread(); return true; } /** * A method that creates and starts a new Thread with a run() method that * begins processing the data streaming from the source instrument. */ private void startThread() { // build the runnable class and implement the run() method Runnable runner = new Runnable() { public void run() { runWork(); } }; // build the Thread and start it, indicating that it has been started readyToStream = true; streamingThread = new Thread(runner, "StreamingThread"); streamingThread.start(); } /** * A method that stops the streaming of data between the source instrument and * the RBNB server. */ public boolean stop() { // return false if the thread is not running if (!isRunning()) { return false; } // stop the thread and disconnect from the RBNB server stopThread(); disconnect(); return true; } /** A method that interrupts the thread created in startThread() */ private void stopThread() { // set the streaming status to false and stop the Thread readyToStream = false; streamingThread.interrupt(); } /** * A method that gets the log configuration file location * * @return logConfigurationFile the log configuration file location */ public String getLogConfigurationFile() { return this.logConfigurationFile; } /** * A method that sets the log configuration file name * * @param logConfigurationFile the log configuration file name */ public void setLogConfigurationFile(String logConfigurationFile) { this.logConfigurationFile = logConfigurationFile; } }