trace/traceviewer/com.nokia.traceviewer.ost/src/com/nokia/traceviewer/ost/OstScrollReader.java
author Jussi Ryoma <ext-jussi.s.ryoma@nokia.com>
Tue, 24 Aug 2010 14:01:48 +0300
changeset 16 72f198be1c1d
parent 11 5b9d4d8641ce
permissions -rw-r--r--
Crash Analyser Carbide Extension 1.4.0

/*
 * Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies). 
 * All rights reserved.
 * This component and the accompanying materials are made available
 * under the terms of "Eclipse Public License v1.0"
 * which accompanies this distribution, and is available
 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
 *
 * Initial Contributors:
 * Nokia Corporation - initial contribution.
 *
 * Contributors:
 *
 * Description:
 *
 * OST ScrollReader class
 *
 */
package com.nokia.traceviewer.ost;

import java.io.IOException;
import java.nio.ByteBuffer;

import com.nokia.traceviewer.engine.DataScrollReader;
import com.nokia.traceviewer.engine.MediaCallback;
import com.nokia.traceviewer.engine.TraceConfiguration;
import com.nokia.traceviewer.engine.TraceProperties;
import com.nokia.traceviewer.engine.TraceViewerGlobals;

/**
 * OST ScrollReader class
 */
public class OstScrollReader extends OstBaseReader implements DataScrollReader,
		OstMessageCallback {

	/**
	 * Number of blocks to process when reader is block-reader
	 */
	private int numberOfBlocks = 1;

	/**
	 * Starting offset when reader is block-reader
	 */
	private int startReadingTracesFrom;

	/**
	 * Number of traces read when reader is block-reader
	 */
	private int numberOfTracesRead;

	/**
	 * Number of bytes received
	 */
	private int bytesRead;

	/**
	 * Number of bytes in previous message
	 */
	private int previousMessageBytes;

	/**
	 * Is this reader blocking
	 */
	private boolean blocking;

	/**
	 * Constructor
	 * 
	 * @param mediaCallback
	 *            callback
	 * @param configuration
	 *            Trace Configuration
	 */
	public OstScrollReader(MediaCallback mediaCallback,
			TraceConfiguration configuration) {
		// OstBaseReader constructor
		super();

		filePath = TraceViewerGlobals.getTraceViewer().getDataReaderAccess()
				.getCurrentDataReader().getFilePath();
		createFileChannel();

		this.mediaCallback = mediaCallback;
		receiveBuffer = ByteBuffer.allocateDirect(RECEIVE_BUFFER_SIZE);
		messageProcessor = new OstMessageProcessor(this, receiveBuffer);
		traceConfiguration = configuration;
		trace = new TraceProperties(configuration);
		trace.byteBuffer = receiveBuffer;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Thread#run()
	 */
	@Override
	public synchronized void run() {
		try {
			running = true;
			receiveBuffer.position(0);
			while (running) {
				// Get bytes in buffer before read operation
				if (receiveBuffer.position() != 0) {
					previousMessageBytes = receiveBuffer.position();
				} else {
					previousMessageBytes = 0;
				}

				// Reads data to buffer
				bytesRead = sourceChannel.read(receiveBuffer);
				if (bytesRead > 0) {

					// If data is found, the processor is used to split
					// thedata into OST messages. processMessage is
					// called for each message found from the buffer and
					// the buffer is re-positioned for next read
					// operation
					messageProcessor.processBuffer();
				} else {
					putToSleep();
				}
			}
		} catch (Throwable t) {
			t.printStackTrace();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.nokia.traceviewer.ost.OstMessageCallback#processMessage(int,
	 * int, int)
	 */
	public boolean processMessage(int msgStart, int msgLen, int headerLen,
			int headerVersion) throws IOException {
		boolean valid = true;
		boolean returnValue = true;
		int protocolId = 0;

		// Create new TraceProperties
		trace = new TraceProperties(traceConfiguration);

		// Save buffer and message and data offsets
		trace.byteBuffer = receiveBuffer;
		trace.messageStart = msgStart;
		trace.messageLength = msgLen;

		// Get protocol ID offset
		int protocolIdOffset = 0;
		if (headerVersion == OST_V01) {
			protocolIdOffset = OST_V01_PROTOCOLID_OFFSET;
		} else if (headerVersion == OST_V05) {
			protocolIdOffset = OST_V05_PROTOCOLID_OFFSET;
		} else if (headerVersion == OST_V10) {
			protocolIdOffset = OST_V10_PROTOCOLID_OFFSET;
		} else if (headerVersion == OST_V00) {
			protocolIdOffset = OST_V00_PROTOCOLID_OFFSET;
		} else {
			// Unsupported header version
			System.out.println("Unsupported header version: " + headerVersion); //$NON-NLS-1$
		}

		// Read protocol ID
		protocolId |= receiveBuffer.get(msgStart + protocolIdOffset)
				& BYTE_MASK;

		// OST Ascii Trace (0x02)
		if (protocolId == OST_ASCII_TRACE_ID && msgLen >= headerLen) {

			// Get the timestamp
			trace.timestamp = messageProcessor.parseTimeStampToNanosecs(
					msgStart, headerLen + OST_ASCII_TRACE_TIMESTAMP_OFFSET);

			// Process the trace
			processOstAsciiTrace(msgStart, msgLen, headerLen);

			// OST Simple Application Trace Protocol (0x03)
		} else if (protocolId == OST_SIMPLE_TRACE_ID) {

			// Get the timestamp
			trace.timestamp = messageProcessor.parseTimeStampToNanosecs(
					msgStart, headerLen + OST_SIMPLE_TRACE_TIMESTAMP_OFFSET);

			// Process the trace
			valid = processOstSimpleTrace(msgStart, headerLen);

			// Unknown protocol ID
		} else {
			trace.binaryTrace = true;
			valid = false;
		}

		// Trace is valid
		if (valid) {
			returnValue = processScrolledTrace(msgStart, msgLen, returnValue);

		}
		return returnValue;
	}

	/**
	 * Processes scrolled trace
	 * 
	 * @param msgStart
	 *            message start offset
	 * @param msgLen
	 *            message length
	 * @param returnValue
	 *            implication of success of processing trace
	 * @return implication of success of processing trace
	 * @throws IOException
	 */
	public boolean processScrolledTrace(int msgStart, int msgLen,
			boolean returnValue) throws IOException {

		// In case of multi part trace, set trace properties now so
		// that DataProcessor can use it properly
		if (trace.bTraceInformation.getMultiPart() != 0) {
			int initialHeaderSize = trace.dataStart - trace.messageStart;
			trace.messageStart = 0;
			trace.messageLength = trace.byteBuffer.capacity();
			trace.dataStart = initialHeaderSize;
			trace.dataLength = trace.messageLength - initialHeaderSize;
		}

		numberOfTracesRead++;
		trace.traceNumber = startReadingTracesFrom + numberOfTracesRead;

		// Not processed full block of traces yet, keep processing
		if (!lastTrace(msgStart, msgLen)) {

			trace.lastTrace = false;
			mediaCallback.processTrace(trace);

			// Last trace
		} else {
			trace.lastTrace = true;
			blocking = true;
			numberOfTracesRead = 0;
			mediaCallback.processTrace(trace);

			putToSleep();
			returnValue = false;
		}
		return returnValue;
	}

	/**
	 * Tells if this trace is the last one to process
	 * 
	 * @param msgStart
	 *            message start offset
	 * @param msgLen
	 *            message length
	 * @return true if this is the last trace
	 * @throws IOException
	 */
	public boolean lastTrace(int msgStart, int msgLen) throws IOException {
		return sourceChannelPosition(msgStart, msgLen) >= sourceChannel.size()
				|| lastTraceToShow() || isBlockSizeRead();
	}

	/**
	 * Checks if we are now read the whole block what we want
	 * 
	 * @return true if block is fully read
	 */
	private boolean isBlockSizeRead() {
		boolean isBlockRead = false;
		if (numberOfTracesRead == TraceViewerGlobals.blockSize * numberOfBlocks) {
			isBlockRead = true;
		}
		return isBlockRead;
	}

	/**
	 * Tells if this is the last trace we want to show during pause because
	 * there propably is more traces in the file
	 * 
	 * @return true if this is the last trace to show during pause
	 */
	public boolean lastTraceToShow() {
		boolean lastTraceToShow = (startReadingTracesFrom + numberOfTracesRead
				+ 1 > TraceViewerGlobals.getTraceViewer().getDataReaderAccess()
				.getCurrentDataReader().getTraceCount());

		return lastTraceToShow;
	}

	/**
	 * Gets position of source channel after this trace
	 * 
	 * @param msgStart
	 *            message start offset
	 * @param msgLen
	 *            message length
	 * @return source channel position after this trace
	 * @throws IOException
	 */
	public long sourceChannelPosition(int msgStart, int msgLen)
			throws IOException {
		return sourceChannel.position() - bytesRead + msgStart + msgLen
				- previousMessageBytes;
	}

	/**
	 * Puts this thread to sleep
	 */
	public void putToSleep() {
		try {
			// Null variables if this reader is only for blocks
			if (TraceViewerGlobals.getTraceViewer().getStateHolder()
					.isScrolling()) {
				receiveBuffer.position(receiveBuffer.capacity());
				numberOfTracesRead = 0;
			}
			if (blocking) {
				this.notifyAll();
				this.wait();
			}
		} catch (InterruptedException e) {
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.nokia.traceviewer.engine.DataScrollReader#setBlockReader(int,
	 * int, boolean)
	 */
	public void setBlockReader(int numberOfBlocks, int startingTrace,
			boolean blocking) {
		this.numberOfBlocks = numberOfBlocks;
		this.startReadingTracesFrom = startingTrace;
		this.blocking = blocking;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.nokia.traceviewer.engine.DataReader#getTracePositionInFile()
	 */
	public long getTracePositionInFile() {
		return 0;
	}
}