connectivity/com.nokia.tcf/src/com/nokia/tcf/impl/TCAPIConnection.java
changeset 2 d760517a8095
child 60 9d2210c8eed2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/connectivity/com.nokia.tcf/src/com/nokia/tcf/impl/TCAPIConnection.java	Tue Mar 24 22:20:21 2009 -0500
@@ -0,0 +1,1025 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "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: 
+*
+*/
+/**
+ * 
+ */
+package com.nokia.tcf.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.text.MessageFormat;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.service.datalocation.Location;
+
+import com.nokia.tcf.api.ITCAPIConnection;
+import com.nokia.tcf.api.ITCConnection;
+import com.nokia.tcf.api.ITCErrorListener;
+import com.nokia.tcf.api.ITCMessage;
+import com.nokia.tcf.api.ITCRealSerialConnection;
+import com.nokia.tcf.api.ITCRealTCPConnection;
+import com.nokia.tcf.api.ITCVirtualSerialConnection;
+import com.nokia.tcf.api.TCFClassFactory;
+import com.nokia.tcf.api.ITCMessageIds;
+import com.nokia.tcf.api.ITCMessageInputStream;
+import com.nokia.tcf.api.ITCMessageOptions;
+import com.nokia.tcf.api.ITCVersion;
+import com.nokia.tcf.Activator;
+import com.nokia.tcf.api.TCErrorConstants;
+
+public class TCAPIConnection implements ITCAPIConnection {
+
+	static {
+		Activator plugin = Activator.getDefault();
+		IPath path = null;
+		String dePath = null;
+		if (plugin != null)
+			path = plugin.getDebuggerPath();
+		if (path != null)
+			dePath = path.toOSString();
+		if (dePath == null) {
+			System.loadLibrary("TCFClient");
+		} else {
+			try{
+				System.load(dePath + java.io.File.separator + "TCFClient.dll");
+			} catch (UnsatisfiedLinkError e) {
+				// if Carbide DLL is not found in DE, 
+				// try to load one from the plugin itself
+				System.loadLibrary("TCFClient");
+			}
+		}
+	}
+	private TCErrorListenerList<ITCErrorListener> errorListenerList;
+	private ITCCookie cookie;		// this client's handle to native
+	private ITCMessageIds messageIds; // this client's message ids
+	private TCMessageInputStream inputStream; // this client's message input stream (not using message file)
+	protected ITCMessageOptions messageOptions; // this client's message options
+	private TCFMonitorThread monitorThread; // the client's native monitor
+	public boolean stopTCFMonitorThread;	//  stream monitor start/stop flag
+	protected IStatus statusOK;
+	protected ITCConnection connection; // the client's connection
+
+	public ITCConnection getConnection() {
+		return this.connection;
+	}
+	public ITCMessageOptions getMessageOptions() {
+		return this.messageOptions;
+	}
+	/**
+	 * Only constructor - fields are created using the public methods
+	 */
+	public TCAPIConnection() {
+		super();
+		this.errorListenerList = new TCErrorListenerList<ITCErrorListener>();
+		this.errorListenerList.clear();
+		this.connection = null;
+		IStatus status = new Status(Status.OK, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_NONE, "OK", null);
+		statusOK = status;
+		this.cookie = new TCCookie(-1, status, false, false);
+		this.inputStream = null;
+		this.messageIds = null;
+		this.messageOptions = null;
+		this.monitorThread = null;
+		this.stopTCFMonitorThread = false;
+	}
+
+	/* (non-Javadoc)
+	 * @see com.nokia.tcf.api.ITCAPIConnection#addErrorListener(com.nokia.tcf.api.ITCErrorListener)
+	 */
+	public IStatus addErrorListener(ITCErrorListener inErrorListener) {
+		IStatus status = statusOK;
+		try {
+			errorListenerList.add(inErrorListener);
+		} catch (NullPointerException e) {
+			int err = (int)TCErrorConstants.TCAPI_ERR_ERRLISTENER_NULL;
+			status = new Status(Status.ERROR, Activator.PLUGIN_ID, err,	TCErrorConstants.getErrorMessage(err), e);
+		}
+//		System.out.printf("addErrorListener status = %s\n", status.getMessage());
+		return status;
+	}
+
+	private IStatus checkConnected() {
+		IStatus status = statusOK;
+		if (this.connection == null || this.cookie.isConnected() == false) {
+			status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_MEDIA_NOT_OPEN,
+					TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_MEDIA_NOT_OPEN), null);
+		}
+		return status;
+	}
+	protected IStatus checkDecodeFormat(String decodeFormat) {
+		IStatus status = statusOK;
+		return status;		
+	}
+	protected IStatus checkConnectionType(ITCConnection inConnection) {
+		IStatus status = statusOK;
+		int type = inConnection.getConnectionType();
+		if (type == ITCConnection.MEDIA_VIRTUALSERIAL) {
+			ITCVirtualSerialConnection c = (ITCVirtualSerialConnection)inConnection;
+			String p = c.getComPort();
+			if (p == null) {
+				status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_MISSING_MEDIA_DATA, 
+						TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_MISSING_MEDIA_DATA), null);
+			}
+		} else if (type == ITCConnection.MEDIA_REALTCP) {
+			ITCRealTCPConnection c = (ITCRealTCPConnection)inConnection;
+			String ip = c.getIpAddress();
+			String p = c.getPort();
+			if (ip == null || p == null) {
+				status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_MISSING_MEDIA_DATA, 
+						TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_MISSING_MEDIA_DATA), null);
+			}
+		} else if (type == ITCConnection.MEDIA_REALSERIAL) {
+			ITCRealSerialConnection c = (ITCRealSerialConnection)inConnection;
+			long err = checkRealSerialSettings(c);
+			if (err != TCErrorConstants.TCAPI_ERR_NONE) {
+				status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)err, TCErrorConstants.getErrorMessage(err), null);
+			}
+		} else {
+			// Add other connection types here
+			status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_UNKNOWN_MEDIA_TYPE,
+					TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_UNKNOWN_MEDIA_TYPE), null);
+		}
+		
+		return status;
+	}
+	private IStatus checkConnection(ITCConnection inConnection) {
+		IStatus status = statusOK;
+		if (this.cookie.isConnected()) {
+			status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_ALREADY_CONNECTED, 
+					TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_ALREADY_CONNECTED), null);
+		}
+		if (inConnection == null) {
+			status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_MISSING_CONNECTION_SPEC, 
+					TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_MISSING_CONNECTION_SPEC), null);
+		}
+		if (status.isOK()) {
+			String decodeFormat = inConnection.getDecodeFormat();
+			status = checkDecodeFormat(decodeFormat);
+		}
+		if (status.isOK()) {
+			long retryI = inConnection.getRetryInterval();
+			long retryT = inConnection.getRetryTimeout();
+			if (retryI == 0 || retryT == 0 || retryI > retryT) {
+				status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_INVALID_RETRY_PERIODS, 
+						TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_INVALID_RETRY_PERIODS), null);
+			}
+		}
+		
+		if (status.isOK()) {
+			status = checkConnectionType(inConnection);
+		}
+	
+		return status;
+	}
+	private long checkRealSerialSettings(ITCRealSerialConnection c) {
+		String[] setting = new String[6];
+		setting[0] = c.getBaudRate();
+		setting[1] = c.getComPort();
+		setting[2] = c.getDataBits();
+		setting[3] = c.getFlowControl();
+		setting[4] = c.getParity();
+		setting[5] = c.getStopBits();
+		for (int i = 0; i < 6; i++) {
+			if (setting[i] == null) {
+				return TCErrorConstants.TCAPI_ERR_MISSING_MEDIA_DATA;
+			}
+		}
+		if ((setting[2] != ITCRealSerialConnection.DATABITS_4) && (setting[2] != ITCRealSerialConnection.DATABITS_5) && (setting[2] != ITCRealSerialConnection.DATABITS_6) &&
+				(setting[2] != ITCRealSerialConnection.DATABITS_7) && (setting[2] != ITCRealSerialConnection.DATABITS_8)) {
+			return TCErrorConstants.TCAPI_ERR_COMM_INVALID_DATABITS;
+		}
+		if ((setting[3] != ITCRealSerialConnection.FLOWCONTROL_HW) && (setting[3] != ITCRealSerialConnection.FLOWCONTROL_NONE) && (setting[3] != ITCRealSerialConnection.FLOWCONTROL_SW)) {
+			return TCErrorConstants.TCAPI_ERR_COMM_INVALID_FLOWCONTROL;
+		}
+		if ((setting[4] != ITCRealSerialConnection.PARITY_EVEN) && (setting[4] != ITCRealSerialConnection.PARITY_NONE) && (setting[4] != ITCRealSerialConnection.PARITY_ODD)) {
+			return TCErrorConstants.TCAPI_ERR_COMM_INVALID_PARITY;
+		}
+		if ((setting[5] != ITCRealSerialConnection.STOPBITS_1) && (setting[5] != ITCRealSerialConnection.STOPBITS_1_5) && (setting[5] != ITCRealSerialConnection.STOPBITS_2)) {
+			return TCErrorConstants.TCAPI_ERR_COMM_INVALID_STOPBITS;
+		}
+		
+		return TCErrorConstants.TCAPI_ERR_NONE;
+	}
+	private IStatus checkMessage(ITCMessage inMessage) {
+		IStatus status = statusOK;
+
+		if (inMessage == null) {
+			// inMessage cannot be null
+			status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_MISSING_MESSAGE,
+					TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_MISSING_MESSAGE), null);
+		} else if (inMessage.size() == 0) {
+			// bytes to send may be 0 if we're doing the header (header is the message)
+			if (this.messageOptions.getMessageEncodeFormat() == ITCMessageOptions.ENCODE_NO_FORMAT) {
+				status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_MISSING_MESSAGE,
+						TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_MISSING_MESSAGE), null);
+			}
+		}
+		if (status.isOK()) {
+			// check options
+			if (inMessage.isUseMyMessageId()) {
+				if (this.messageOptions.getMessageEncodeFormat() == ITCMessageOptions.ENCODE_NO_FORMAT) {
+					// use my id, but don't encode = error
+					status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_MESSAGE_OPTIONS_CONFLICT,
+							TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_MESSAGE_OPTIONS_CONFLICT), null);
+				} else {
+					// use my id, and encode = OK
+				}
+			} else {
+				if (this.messageOptions.getMessageEncodeFormat() == ITCMessageOptions.ENCODE_NO_FORMAT) {
+					// don't use my id, and don't encode = OK
+				} else {
+					// don't use my id, but encode = warning (we'll go ahead send this message raw)
+					status = new Status(Status.WARNING, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_MESSAGE_OPTIONS_CONFLICT,
+							TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_MESSAGE_OPTIONS_CONFLICT), null);
+				}
+			}
+		}
+		return status;
+	}
+	private IStatus checkMessageIds(ITCMessageIds inMessageIds) {
+		IStatus status = statusOK;
+
+		if (inMessageIds == null || inMessageIds.size() == 0) {
+			status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_NO_MESSAGESIDS_REGISTERED,
+					TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_NO_MESSAGESIDS_REGISTERED), null);
+		}
+		if (status.isOK()) {
+			if (inMessageIds.size() > 256) {
+				status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_MESSAGEID_MAXIMUM,
+						TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_MESSAGEID_MAXIMUM), null);
+			}
+		}
+		return status;
+	}
+
+
+	private IStatus checkMessageOptions(ITCMessageOptions inMessageOptions) {
+		IStatus status = statusOK;
+
+		if (inMessageOptions == null) {
+			status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_MISSING_MESSAGE_OPTIONS,
+					TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_MISSING_MESSAGE_OPTIONS), null);
+		}
+//		if (status.isOK()) {
+//			long option = inMessageOptions.getMessageDestination();
+//			String file = inMessageOptions.getMessageFile().toOSString();
+//			if (option == ITCMessageOptions.DESTINATION_CLIENTFILE) {
+//				status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_FEATURE_NOT_IMPLEMENTED,
+//					TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_FEATURE_NOT_IMPLEMENTED), null);
+//			}
+//		}
+		
+		if (status.isOK()) {
+			long option = inMessageOptions.getMessageEncodeFormat();
+			switch ((int)option) {
+			case (int)ITCMessageOptions.ENCODE_NO_FORMAT:
+			case (int)ITCMessageOptions.ENCODE_FORMAT:
+			case (int)ITCMessageOptions.ENCODE_TRK_FORMAT:
+				break;
+			default:
+				status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_INVALID_ENCODE_FORMAT,
+						TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_INVALID_ENCODE_FORMAT), null);
+			}
+		}
+		if (status.isOK()) {
+			long option = inMessageOptions.getUnWrapFormat();
+			switch ((int)option) {
+			case (int)ITCMessageOptions.UNWRAP_DELETE_HEADERS:
+			case (int)ITCMessageOptions.UNWRAP_LEAVE_HEADERS:
+				break;
+			default:
+				status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_INVALID_MESSAGE_UNWRAP_OPTION,
+						TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_INVALID_MESSAGE_UNWRAP_OPTION), null);
+			}
+		}
+		
+		if (status.isOK()) {
+			long bufferSize = inMessageOptions.getInputStreamSize();
+			if (bufferSize <= 0) {
+				status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_INVALID_STREAM_BUFFER_SIZE,
+						TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_INVALID_STREAM_BUFFER_SIZE), null);
+			}
+		}
+		
+		return status;
+	}
+
+	protected IStatus checkConnectOptions(ITCConnection inConnection,
+			ITCMessageOptions inMessageOptions, ITCMessageIds inMessageIds) {
+		
+		IStatus status = statusOK;
+
+		status = checkConnection(inConnection);
+		
+		if (status.isOK()) {
+			status = checkMessageOptions(inMessageOptions);
+		}
+		if (status.isOK()) {
+			status = checkMessageIds(inMessageIds);
+		}
+		return status;
+	}
+	protected IStatus finishConnect(int type, String[] settings, 
+			ITCConnection inConnection, ITCMessageOptions inMessageOptions, ITCMessageIds inMessageIds) {
+		IStatus status = statusOK;
+		// connect
+		long[] clientId = new long[1];
+		clientId[0] = -1;
+		long[] options = new long[3];
+		options[0] = inConnection.getRetryInterval();		// connection options
+		options[1] = inConnection.getRetryTimeout();
+		options[2] = 0;
+		long[] moptions = new long[2];
+		moptions[0] = inMessageOptions.getUnWrapFormat();
+		moptions[1] = inMessageOptions.getOSTVersion();
+		String filePath = null;
+		if (inMessageOptions.getMessageDestination() == ITCMessageOptions.DESTINATION_CLIENTFILE) {
+			filePath = inMessageOptions.getMessageFile().toOSString();
+			try {
+				ensureWritableFile(filePath);
+			} catch (IOException e) {
+				String msg = e.getMessage();
+				long err = TCErrorConstants.TCAPI_ERR_CREATE_FILE;
+				String tcErr = String.format("%s OSError: %s", TCErrorConstants.getErrorMessage(err), msg);
+				status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, 
+						(int)TCErrorConstants.TCAPI_ERR_CREATE_FILE, tcErr, e);
+			}
+		}
+		
+		try {
+			long ret = nativeConnect(type, options, settings, moptions, filePath, clientId); 
+			if (ret == TCErrorConstants.TCAPI_ERR_NONE) {
+				this.cookie.setClientId(clientId[0]);
+				this.cookie.setConnected(true);
+				this.connection = inConnection;
+				this.messageOptions = inMessageOptions;
+			} else {
+				status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)ret, TCErrorConstants.getErrorMessage(ret), null);
+			}
+		} catch (Exception e) {
+			// exception is thrown ONLY when err = TCAPI_ERR_WHILE_CONFIGURING_MEDIA from native
+			// and the message is the OS error generated
+			String msg = e.getMessage();
+			long ret = TCErrorConstants.TCAPI_ERR_WHILE_CONFIGURING_MEDIA;
+			String tcErr = String.format("%s OSError: %s", TCErrorConstants.getErrorMessage(ret), msg);
+			status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)ret, tcErr, null);
+		}
+		// send message ids to capture
+		if (status.isOK()) {
+			int number = (int)inMessageIds.size();
+			byte[] ids = new byte[number];
+			for (int i = 0; i < number; i++) {
+				ids[i] = inMessageIds.getMessageIds().get(i);
+			}
+			long ret = nativeSetMessageIds(this.cookie.getClientId(), ids);
+			if (ret == TCErrorConstants.TCAPI_ERR_NONE) {
+				this.messageIds = inMessageIds;
+			} else {
+				status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)ret, TCErrorConstants.getErrorMessage(ret), null);
+			}
+		}
+		// setup input stream
+		if (status.isOK() && inMessageOptions.getMessageDestination() == ITCMessageOptions.DESTINATION_INPUTSTREAM) {
+			inputStream = new TCMessageInputStream(this,
+					inMessageOptions.getInputStreamSize(),
+					cookie.getClientId());
+			try {
+				inputStream.open();
+			} catch (IOException e) {
+				// stream didn't open
+				status = new Status(Status.ERROR, Activator.PLUGIN_ID, e.getMessage(), e);
+				e.printStackTrace();
+			}
+		}
+		// create error monitor
+		if (status.isOK()) {
+			String monitorName = String.format("TCFMonitor%d", this.cookie.getClientId());
+			monitorThread = new TCFMonitorThread(this, monitorName);
+			stopTCFMonitorThread = false;
+			monitorThread.start();
+		}
+		
+		// start capture
+		if (status.isOK()) {
+			long ret = nativeStart(this.cookie.getClientId());
+			if (ret == TCErrorConstants.TCAPI_ERR_NONE) {
+				this.cookie.setMessageProcessing(true);
+			} else {
+				// error in starting capture
+				status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)ret, TCErrorConstants.getErrorMessage(ret), null);
+			}
+		}
+		if (!status.isOK()) {
+			// an error occurred along the way - unravel what we've done
+			if (this.cookie.isMessageProcessing()) {
+				long ret = nativeStop(this.cookie.getClientId());
+				// ignore error
+				this.cookie.setMessageProcessing(false);
+			}
+			if (this.monitorThread != null) {
+				this.stopTCFMonitorThread = true;
+				try {
+					this.monitorThread.join();
+				} catch (InterruptedException e) {
+				}
+				this.monitorThread = null;
+			}
+			if (this.inputStream != null && this.inputStream.isOpen()) {
+				try {
+					this.inputStream.close();
+				} catch (IOException e) {
+				}
+				this.inputStream = null;
+			}
+			if (this.cookie.isConnected()) {
+				long ret = nativeDisconnect(this.getClientId());
+				this.cookie.setConnected(false);
+				this.cookie.setClientId(-1);
+			}
+		}
+		return status;
+	}
+	/* (non-Javadoc)
+	 * @see com.nokia.tcf.api.ITCAPIConnection#connect(com.nokia.tcf.api.ITCConnection, com.nokia.tcf.api.ITCMessageOptions, com.nokia.tcf.api.ITCMessageIds)
+	 */
+	public IStatus connect(ITCConnection inConnection,
+			ITCMessageOptions inMessageOptions, ITCMessageIds inMessageIds) {
+		
+		IStatus status = checkConnectOptions(inConnection, inMessageOptions, inMessageIds);
+		String[] settings = null;
+		int type = 0;
+
+		// do connect
+		if (status.isOK()) {
+			settings = null;
+			type = inConnection.getConnectionType();
+			switch(type) {
+			case ITCConnection.MEDIA_REALTCP: {
+				settings = new String[3];
+				ITCRealTCPConnection t = (ITCRealTCPConnection)inConnection;
+				settings[0] = t.getIpAddress();
+				settings[1] = t.getPort();
+				settings[2] = t.getDecodeFormat().toLowerCase();
+				break;
+			}
+			case ITCConnection.MEDIA_VIRTUALSERIAL: {
+				settings = new String[2];
+				ITCVirtualSerialConnection s = (ITCVirtualSerialConnection)inConnection;
+				settings[0] = s.getComPort();
+				settings[1] = s.getDecodeFormat().toLowerCase();
+				break;
+			}
+			case ITCConnection.MEDIA_REALSERIAL: {
+				settings = new String[7];
+				ITCRealSerialConnection s = (ITCRealSerialConnection)inConnection;
+				settings[0] = s.getComPort();
+				settings[1] = s.getBaudRate();
+				settings[2] = s.getDataBits();
+				settings[3] = s.getParity();
+				settings[4] = s.getStopBits();
+				settings[5] = s.getFlowControl();
+				settings[6] = s.getDecodeFormat().toLowerCase();
+				break;
+			}
+			case ITCConnection.MEDIA_USB: {
+				settings = new String[1];
+				break;
+			}
+			default:
+				// Add other connection types here - error already checked in checkConnection()
+				break;
+			}
+		}
+		return finishConnect(type, settings, inConnection, inMessageOptions, inMessageIds);
+	}
+	private void ensureWritableFile(String filePath) throws IOException {
+		// ensure file path points to a writable regular file
+		IPath path = new Path(filePath);
+		File file = path.toFile();
+		if (!file.exists()) {
+			file.createNewFile();
+		}
+		else { // file exists
+			if (file.isDirectory()) {
+				throw new IOException(MessageFormat.format("Path is a directory: {0}", filePath));
+			}
+			else if (!file.canWrite()) {
+				throw new IOException(MessageFormat.format("File exists and is not writable: {0}", filePath));
+			}
+		}
+	}
+	
+	/* (non-Javadoc)
+	 * @see com.nokia.tcf.api.ITCAPIConnection#connect(com.nokia.tcf.api.ITCMessageOptions, com.nokia.tcf.api.ITCMessageIds)
+	 */
+	public IStatus connect(ITCMessageOptions inMessageOptions, ITCMessageIds inMessageIds) {
+		// not currently implemented or tested
+		long ret = TCErrorConstants.TCAPI_ERR_FEATURE_NOT_IMPLEMENTED;
+		IStatus status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)ret, TCErrorConstants.getErrorMessage(ret), null);
+		return status;
+	}
+
+	/* (non-Javadoc)
+	 * @see com.nokia.tcf.api.ITCAPIConnection#disconnect()
+	 */
+	public IStatus disconnect() {
+		IStatus status = statusOK;
+		
+		IStatus connectStatus = checkConnected();
+		// ignore error
+		if (connectStatus.isOK()) {
+			if (this.cookie.isMessageProcessing()) {
+				long ret = nativeStop(this.cookie.getClientId());
+				this.cookie.setMessageProcessing(false);
+				if (ret != TCErrorConstants.TCAPI_ERR_NONE) {
+					status = new Status(IStatus.ERROR,Activator.PLUGIN_ID, (int)ret, TCErrorConstants.getErrorMessage(ret), null);
+				}
+			}
+			if (this.monitorThread != null) {
+				this.stopTCFMonitorThread = true;
+				this.monitorThread.stop = true;
+				try {
+					this.monitorThread.join();
+				} catch (InterruptedException e) {
+				}
+				this.monitorThread = null;
+			}
+			if (this.inputStream != null && this.inputStream.isOpen()) {
+				try {
+					this.inputStream.close();
+				} catch (IOException e) {
+				}
+				this.inputStream = null;
+			}
+			if (this.cookie.isConnected()) {
+				long ret = nativeDisconnect(this.cookie.getClientId());
+				if (ret == TCErrorConstants.TCAPI_ERR_NONE) {
+					this.cookie.setConnected(false);
+					this.cookie.setClientId(-1);
+				} else {
+					// error from nativeDisconnect
+					status = new Status(Status.ERROR,Activator.PLUGIN_ID, (int)ret, TCErrorConstants.getErrorMessage(ret), null);
+				}
+			}
+		}
+		return status;
+	}
+
+	// private methods
+	/**
+	 * This is called from TCFMonitorThread to send errors to registered listeners
+	 */
+	public void fireErrorListeners(long errorCode, String errorString) {
+		int s = this.errorListenerList.size();
+//		System.out.printf("fireErrorListeners s = %d\n", s);
+		for (int i = 0; i < s; i++) {
+			ITCErrorListener e = (ITCErrorListener)this.errorListenerList.get(i);
+			if (e != null) {
+				int errorStatus = Status.ERROR;
+				if (errorCode == TCErrorConstants.TCAPI_INFO_COMM_RECONNECTED)
+					errorStatus = Status.INFO;
+				IStatus status = new Status(errorStatus, Activator.PLUGIN_ID, (int)errorCode, errorString, null);
+				e.errorOccurred(status);
+			}
+		}
+	}
+
+	public long getClientId() {
+		return this.cookie.getClientId();
+	}
+
+	/* (non-Javadoc)
+	 * @see com.nokia.tcf.api.ITCAPIConnection#getConnections()
+	 */
+	public ITCConnection[] getConnections() {
+		IStatus status = statusOK;
+		ITCConnection[] connections = null;
+		long numberConnections = 0;
+		long[] number = new long[1];
+		long ret = nativeGetNumberConnections(number);
+		if (ret == TCErrorConstants.TCAPI_ERR_NONE) {
+			numberConnections = number[0];
+		} else {
+			// error processing from nativeGetNumberConnections
+			status = new Status(Status.ERROR,Activator.PLUGIN_ID, (int)ret, TCErrorConstants.getErrorMessage(ret), null);
+		}
+		if (numberConnections > 0)
+		{
+			connections = new ITCConnection[(int)numberConnections];
+			for (int inIndex = 0; inIndex < numberConnections; inIndex++)
+			{
+				int[] type = new int[1];
+				ret = nativeGetTypeOfConnection(inIndex, type);
+				switch ((int)type[0]) {
+				case (int)ITCConnection.MEDIA_VIRTUALSERIAL: {
+					ITCVirtualSerialConnection outConnection = (ITCVirtualSerialConnection)TCFClassFactory.createITCVirtualSerialConnection(null);
+					int[] outType = new int[1];
+					long[] outOptions = new long[3];
+					String[] outSettings = new String[1];
+					ret = nativeGetConnectionSettings(inIndex, outType, outOptions, outSettings);
+					if (ret == TCErrorConstants.TCAPI_ERR_NONE) {
+						outConnection.setConnectionType(outType[0]);
+						outConnection.setRetryInterval(outOptions[0]);
+						outConnection.setRetryTimeout(outOptions[1]);
+						outConnection.setDecodeFormat(convertDecodeFormat(outOptions[2]));
+						outConnection.setComPort(outSettings[0]);
+						
+						connections[inIndex] = outConnection;
+					} else {
+						// error processing from nativeGetConnectionSettings
+						status = new Status(Status.ERROR,Activator.PLUGIN_ID, (int)ret, TCErrorConstants.getErrorMessage(ret), null);
+					}
+					break;
+				}
+				case (int)ITCConnection.MEDIA_REALTCP: {
+					ITCRealTCPConnection outConnection = (ITCRealTCPConnection)TCFClassFactory.createITCRealTCPConnection(null, null);
+					int[] outType = new int[1];
+					long[] outOptions = new long[3];
+					String[] outSettings = new String[2];
+					ret = nativeGetConnectionSettings(inIndex, outType, outOptions, outSettings);
+					if (ret == TCErrorConstants.TCAPI_ERR_NONE) {
+						outConnection.setConnectionType(outType[0]);
+						outConnection.setRetryInterval(outOptions[0]);
+						outConnection.setRetryTimeout(outOptions[1]);
+						outConnection.setDecodeFormat(convertDecodeFormat(outOptions[2]));
+						outConnection.setIpAddress(outSettings[0]);
+						outConnection.setPort(outSettings[1]);
+						
+						connections[inIndex] = outConnection;
+					} else {
+						// error processing from nativeGetConnectionSettings
+						status = new Status(Status.ERROR,Activator.PLUGIN_ID, (int)ret, TCErrorConstants.getErrorMessage(ret), null);
+					}
+					break;
+				}
+				case (int)ITCConnection.MEDIA_REALSERIAL: {
+					ITCRealSerialConnection outConnection = (ITCRealSerialConnection)TCFClassFactory.createITCRealSerialConnection(null);
+					int[] outType = new int[1];
+					long[] outOptions = new long[6];
+					String[] outSettings = new String[6];
+					ret = nativeGetConnectionSettings(inIndex, outType, outOptions, outSettings);
+					if (ret == TCErrorConstants.TCAPI_ERR_NONE) {
+						outConnection.setConnectionType(outType[0]);
+						outConnection.setRetryInterval(outOptions[0]);
+						outConnection.setRetryTimeout(outOptions[1]);
+						outConnection.setDecodeFormat(convertDecodeFormat(outOptions[2]));
+						outConnection.setComPort(outSettings[0]);
+						outConnection.setBaudRate(outSettings[1]);
+						outConnection.setDataBits(outSettings[2]);
+						outConnection.setParity(outSettings[3]);
+						outConnection.setStopBits(outSettings[4]);
+						outConnection.setFlowControl(outSettings[5]);
+						
+						connections[inIndex] = outConnection;
+					} else {
+						// error processing from nativeGetConnectionSettings
+						status = new Status(Status.ERROR,Activator.PLUGIN_ID, (int)ret, TCErrorConstants.getErrorMessage(ret), null);
+					}
+					break;
+				}
+				case (int)ITCConnection.MEDIA_USB: {
+					break;
+				}
+				default:
+					// Add other connection types here
+					break;
+				}
+			}
+		}
+		return connections;
+	}
+
+	protected String convertDecodeFormat(long decodeFormat) {
+		if (decodeFormat == 1) {
+			return "platsim";
+		}
+		if (decodeFormat == 2) {
+			return "ost";
+		}
+		if (decodeFormat == 3) {
+			return "rawtrk";
+		}
+		return "ost";
+	}
+	/* (non-Javadoc)
+	 * @see com.nokia.tcf.api.ITCAPIConnection#getInputStream()
+	 */
+	public ITCMessageInputStream getInputStream() {
+		return this.inputStream;
+	}
+
+	/* (non-Javadoc)
+	 * @see com.nokia.tcf.api.ITCAPIConnection#getVersions()
+	 */
+	public ITCVersion[] getVersions() {
+		IStatus status = statusOK;
+		ITCVersion[] versions = null;
+		status = checkConnected();
+		if (status.isOK()) {
+			// we're connected call native
+			long numberVersions = nativeGetNumberVersionEntities(this.cookie.getClientId());
+			if (numberVersions > 0) {
+				versions = new TCVersion[(int)numberVersions];
+				String[] versStrings = new String[(int)numberVersions];
+				long numberGotten = nativeGetVersion(this.cookie.getClientId(), numberVersions, versStrings);
+				for (int i = 0; i < numberGotten; i++) {
+					versions[i] = new TCVersion(versStrings[i]);
+				}
+			}
+		}
+		return versions;
+	}
+	/* (non-Javadoc)
+	 * @see com.nokia.tcf.api.ITCAPIConnection#removeErrorListener(com.nokia.tcf.api.ITCErrorListener)
+	 */
+	public IStatus removeErrorListener(ITCErrorListener inErrorListener) {
+		IStatus status = statusOK;
+//		System.out.printf("removeErrorListener\n");
+		this.errorListenerList.remove(inErrorListener);
+		return status;
+	}
+	/* (non-Javadoc)
+	 * @see com.nokia.tcf.api.ITCAPIConnection#sendMessage(com.nokia.tcf.api.ITCMessage)
+	 */
+	public IStatus sendMessage(ITCMessage inMessage) {
+		IStatus status = statusOK;
+		status = checkConnected();
+		if (status.isOK()) {
+			// we are connected are we processing?
+			if (this.cookie.isMessageProcessing()) {
+				// we are running, check message
+				status = checkMessage(inMessage);
+				if (status.getSeverity() != Status.ERROR) {
+					// Status.OK or Status.WARNING (still attempt to send on warning)
+					// Encode if option is set
+
+					long[] formattingOptions = new long[5];
+					formattingOptions[0] = 0;
+					formattingOptions[1] = messageOptions.getMessageEncodeFormat();
+					formattingOptions[2] = messageOptions.getOSTVersion();
+					formattingOptions[3] = inMessage.getMyMessageId();
+					formattingOptions[4] = (inMessage.isUseMyMessageId() == true) ? 1 : 0;
+					String[] settings = new String[1];
+					settings[0] = connection.getDecodeFormat().toLowerCase();
+					try {
+						long ret = TCErrorConstants.TCAPI_ERR_NONE;
+						if (inMessage == null) { // OK if we're just sending a header
+							ret = nativeSendMessage(this.cookie.getClientId(), formattingOptions, settings, null);
+						} else {
+							ret = nativeSendMessage(this.cookie.getClientId(), formattingOptions, settings, inMessage.getMessage());
+						}
+						if (ret != TCErrorConstants.TCAPI_ERR_NONE) {
+							status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)ret, TCErrorConstants.getErrorMessage(ret), null);
+						}
+					} catch (Exception e) {
+						// exception is thrown ONLY when err = TCAPI_ERR_COMM_ERROR from native
+						// message is OS Error
+						String msg = e.getMessage();
+						long ret = TCErrorConstants.TCAPI_ERR_COMM_ERROR;
+						String tcErr = String.format("%s OSError: %s", TCErrorConstants.getErrorMessage(ret), msg);
+						status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)ret, tcErr, null);
+					}
+				}
+			} else {
+				// we are stopped
+				status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_ROUTING_STOPPED,
+						TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_ROUTING_STOPPED), null);
+			}
+		}
+		return status;
+	}
+	/* (non-Javadoc)
+	 * @see com.nokia.tcf.api.ITCAPIConnection#setTCMessageIds(com.nokia.tcf.api.ITCMessageIds)
+	 */
+	public IStatus setTCMessageIds(ITCMessageIds inMessageIds) {
+		IStatus status = statusOK;
+		status = checkMessageIds(inMessageIds);
+		if (status.isOK()) {
+			// input is OK
+			status = checkConnected();
+			if (status.isOK()) {
+				// connected
+				if (this.cookie.isMessageProcessing()) {
+					// must be stopped to set new IDs
+					status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)TCErrorConstants.TCAPI_ERR_ROUTING_IN_PROGRESS,
+							TCErrorConstants.getErrorMessage(TCErrorConstants.TCAPI_ERR_ROUTING_IN_PROGRESS), null);
+				}
+			}
+		}
+		if (status.isOK()) {
+			// everything OK, so we can save our IDs and register them
+			this.messageIds = inMessageIds;
+			int size = (int)inMessageIds.size();
+			byte[] messageids = new byte[size];
+			for (int i = 0; i < size; i++) {
+				messageids[0] = inMessageIds.getMessageIds().get(i);
+			}
+			long ret = nativeSetMessageIds(this.cookie.getClientId(), messageids);
+			if (ret != TCErrorConstants.TCAPI_ERR_NONE) {
+				status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)ret,
+						TCErrorConstants.getErrorMessage(ret), null);
+			}
+		}
+		return status;
+	}
+	/* (non-Javadoc)
+	 * @see com.nokia.tcf.api.ITCAPIConnection#start()
+	 */
+	public IStatus start() {
+		IStatus status = statusOK;
+		// check connected
+		status = checkConnected();
+		if (status.isOK()) {
+			if (this.cookie.isMessageProcessing() == false) {
+				// call native
+				long ret = nativeStart(this.cookie.getClientId());
+				if (ret == TCErrorConstants.TCAPI_ERR_NONE) {
+					this.cookie.setMessageProcessing(true);
+				} else {
+					status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)ret, TCErrorConstants.getErrorMessage(ret), null);
+				}
+			}
+		}
+		
+		return status;
+	}
+	/* (non-Javadoc)
+	 * @see com.nokia.tcf.api.ITCAPIConnection#stop()
+	 */
+	public IStatus stop() {
+		IStatus status = statusOK;
+		status = checkConnected();
+		if (status.isOK()) {
+			if (this.cookie.isMessageProcessing()) {
+				long ret = nativeStop(this.cookie.getClientId());
+				if (ret == TCErrorConstants.TCAPI_ERR_NONE) {
+					this.cookie.setMessageProcessing(false);
+				} else {
+					status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)ret, TCErrorConstants.getErrorMessage(ret), null);
+				}
+			}
+		}
+		return status;
+	}
+	/* (non-Javadoc)
+	 * @see com.nokia.tcf.api.ITCAPIConnection#testConnection()
+	 */
+	public IStatus testConnection() {
+		IStatus status = statusOK;
+		status = checkConnected();
+		if (status.isOK()) {
+			long ret = nativeTestConnection(this.cookie.getClientId());
+			if (ret != TCErrorConstants.TCAPI_ERR_NONE) {
+				status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)(ret), TCErrorConstants.getErrorMessage((int)ret), null);
+			}
+		}
+		return status;
+	}
+	protected IStatus doTestConnection(int type, String[] settings, ITCConnection inConnection) {
+		IStatus status = statusOK;
+		// test connection
+		long[] options = new long[3];
+		options[0] = inConnection.getRetryInterval();		// connection options
+		options[1] = inConnection.getRetryTimeout();
+		options[2] = 0;
+		long ret = nativeTestConnection(type, options, settings);
+		if (ret != TCErrorConstants.TCAPI_ERR_NONE) {
+			status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)ret, TCErrorConstants.getErrorMessage(ret), null);
+		}
+		return status;
+	}
+	/* (non-Javadoc)
+	 * @see com.nokia.tcf.api.ITCAPIConnection#testConnection(com.nokia.tcf.api.ITCConnection)
+	 */
+	public IStatus testConnection(ITCConnection inConnection) {
+		IStatus status = statusOK;
+		String[] settings = null;
+		int type = inConnection.getConnectionType();
+		switch(type) {
+		case ITCConnection.MEDIA_REALSERIAL:
+		{
+			settings = new String[7];
+			ITCRealSerialConnection s = (ITCRealSerialConnection)inConnection;
+			settings[0] = s.getComPort();
+			settings[1] = s.getBaudRate();
+			settings[2] = s.getDataBits();
+			settings[3] = s.getParity();
+			settings[4] = s.getStopBits();
+			settings[5] = s.getFlowControl();
+			settings[6] = s.getDecodeFormat().toLowerCase();
+		}
+			break;
+		case ITCConnection.MEDIA_REALTCP:
+		{
+			settings = new String[3];
+			ITCRealTCPConnection s = (ITCRealTCPConnection)inConnection;
+			settings[0] = s.getIpAddress();
+			settings[1] = s.getPort();
+			settings[2] = s.getDecodeFormat().toLowerCase();
+		}	
+			break;
+		case ITCConnection.MEDIA_USB:
+		{
+			settings = new String[1];
+		}
+			break;
+		case ITCConnection.MEDIA_VIRTUALSERIAL:
+		{
+			settings = new String[2];
+			ITCVirtualSerialConnection s = (ITCVirtualSerialConnection)inConnection;
+			settings[0] = s.getComPort();
+			settings[1] = s.getDecodeFormat().toLowerCase();
+		}
+			break;
+		default:
+			long err = TCErrorConstants.TCAPI_ERR_MEDIA_NOT_SUPPORTED;
+			status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)err, TCErrorConstants.getErrorMessage((int)err), null);
+			break;
+		}
+		
+		if (status.isOK()) {
+			status = doTestConnection(type, settings, inConnection);
+/*			// test connection
+			long[] options = new long[3];
+			options[0] = inConnection.getRetryInterval();		// connection options
+			options[1] = inConnection.getRetryTimeout();
+			options[2] = inConnection.getDecodeFormat();
+			long ret = nativeTestConnection(type, options, settings);
+			if (ret != TCErrorConstants.TCAPI_ERR_NONE) {
+				status = new Status(Status.ERROR, Activator.PLUGIN_ID, (int)ret, TCErrorConstants.getErrorMessage(ret), null);
+			} */
+		}
+		return status;
+	}
+	public IStatus clearMessageFile() {
+		IStatus status = statusOK;
+		IStatus connStatus = checkConnected();
+		if (connStatus.isOK()) {
+			if (messageOptions.getMessageDestination() == ITCMessageOptions.DESTINATION_CLIENTFILE) {
+				if (messageOptions.getMessageFile() != null) {
+					long ret = nativeClearFile(cookie.getClientId());
+					if (ret != TCErrorConstants.TCAPI_ERR_NONE) {
+						status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, (int)ret, TCErrorConstants.getErrorMessage(ret), null);
+					}
+				}
+			}
+		}
+		return status;
+	}
+
+	// natives
+	// connect/disconnect
+	private native long nativeConnect(int inType, long[] inOptions, String[] inSettings, long[] inMessageOptions, String inFilePath, long[] outClientId);
+	private native long nativeDisconnect(long inClientId); 
+	// connections
+	protected native long nativeGetNumberConnections(long[] outNumber);
+	protected native long nativeGetTypeOfConnection(long inIndex, int[] outType);
+	protected native long nativeGetConnectionSettings(long inIndex, int[] outType, long[] outOptions, String[] outSettings);
+	// port handling errors
+	public native boolean nativePollError(long inClienId, int[] outErrorCode, boolean[] outHasOSErrorCode, long[] outOSErrorCode);
+	// versions
+	private native long nativeGetNumberVersionEntities(long inClientId);
+	private native long nativeGetVersion(long inClientId, long inNumToGet, String[] outVersion);
+	// input stream
+	public native long nativePollInputStream(long inClientId, long[] outNumberTotalMessages);
+	public native long nativePollInputStream2(long inClientId, long inNumberMessagesToPeek, long[] outNumberMessagesPeeked, long[] outNumberBytesPeeked);
+	public native long nativeGetInputStreamMessageBytes(long inClientId, long inNumberMessagesToPeek, long[] outNumberBytesPerMessage);
+	public native long nativeReadInputStream(long inClientId, long inNumberMessagesToRead, long[] outNumberMessagesRead, long[] outNumberBytesRead, long inNumberMaxBytes, byte[] outMessages);
+	public native long nativeOpenInputStream(long inClientId, String inBaseFilePath, long inInputStreamSize, boolean inOverFlowToFile);
+	public native long nativeCloseInputStream(long inClientId);
+	// message file
+	private native long nativeClearFile(long inClientId);
+	// send message
+	private native long nativeSendMessage(long inClientId, long[] inFormattingOptions, String[] inSettings, byte[] inMessage);
+	// register message IDs
+	private native long nativeSetMessageIds(long inClientId, byte[] inMessageIds);
+	// start/stop processing
+	private native long nativeStart(long inClientId);
+	private native long nativeStop(long inClientId);
+	// test connections
+	private native long nativeTestConnection(int inType, long[] inOptions, String[] inSettings);
+	private native long nativeTestConnection(long inClientId);
+	// start/stop server - done from plugin activator start/stop methods
+	public native long nativeStartServer();
+	public native long nativeStopServer();
+}