/*  Copyright (C) MOXA Inc. All rights reserved.

    This software is distributed under the terms of the
    MOXA License.  See the file COPYING-MOXA for details.
*/

/*
    MxUPortAPI Demo

    A demonstration program uses MxUPortAPI for UPort devices.

    2013-04-29	Jason Chen
*/

package com.moxa.mxuportapidemo;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.moxa.mxuportapidemo.R;
import com.moxa.mxuportapi.MxException;
import com.moxa.mxuportapi.MxUPort;
import com.moxa.mxuportapi.MxException.ErrorCode;
import com.moxa.mxuportapi.MxUPort.*;
import com.moxa.mxuportapi.MxUPortService;
import com.moxa.mxuportapi.Version;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Scroller;
import android.widget.Spinner;
import android.widget.TextView;

public class MainActivity extends Activity {
	
	private static final String TAG = "com.moxa.mxupapidemo.MainActivity";
	
    private UsbManager mUsbManager;
    private boolean mExitThread = false;
    private List<MxUPort> mPortList = null;
    private MxUPort mCurrentUPort = null;
    private int mPortSelection = -1;
    private int mBaudRate = -1;
    private int mDataBits = -1;
    private int mParity = -1;
    private int mStopBits = -1;
    private int mFlowControl = -1;
    
    private ArrayAdapter<String> mPortListAdapter;
    private ArrayAdapter<CharSequence> mBaudRateAdapter;
    private ArrayAdapter<CharSequence> mDataBitsAdapter;
    private ArrayAdapter<CharSequence> mParityAdapter;
    private ArrayAdapter<CharSequence> mStopBitsAdapter;
    private ArrayAdapter<CharSequence> mFlowControlAdapter;
    
    private static EditText mLogText;
    private EditText mWriteEditCtrl;
    private EditText mSetPortNameCtrl;
    
    private Button mOpenButton;
    private Button mCloseButton;
    private Button mWriteButton;
    private Button mPropertyButton;
    private Button mFlushButton;
    private Button mRTSButton;
    private Button mDTRButton;
    private Spinner mBaudRateSpinner;
    private Spinner mParitySpinner;
    private Spinner mFlowSpinner;
    private Spinner mDataBitsSpinner;
    private Spinner mStopBitsSpinner;
    
    private int mRtsEnable = MxUPort.RTS_ON;
    private int mDtrEnable = MxUPort.DSR_ON;
    
    private List<ReadText> mReadTextList = new ArrayList<ReadText>();
    private Object mReadTextLock = new Object();
    
    Thread mLogThread = null;
    Handler mLogHandler = new Handler();
    
    class ReadText implements Runnable {
    	
    	private String mStr = null;
    	private byte[] bufText = null;
    	private ByteBuffer mBuf = null;
    	
    	ReadText(String s){
    		mStr = s;
    	}
    	
    	ReadText(byte[] buf, int length){
    		bufText = Arrays.copyOf(buf, length);
    		mBuf = ByteBuffer.wrap( bufText );
    	}
    	
    	@Override
	    public void run() {
    		
    		byte ch = 0;
    		
    		if( mStr!= null ){
    			mLogText.append(mStr);
    		}
    		
    		if( mBuf!=null ){
    			for( int i=0; i<mBuf.limit(); i++ ){
    				ch = mBuf.get(i);
    				if( (ch<32 || ch>126) && ch!=0x0d && ch!=0x0a ){
    					mLogText.append(String.format("[%02X]", ch));
    				} else {
    					mLogText.append(String.format("%c", ch));
    				}    				
    			}
    		}
    	}
    	
    }
    
    private void doClosePort(){
		mCloseButton.setEnabled(false);
		
		mExitThread = true;
		if( mCurrentUPort != null ){
			try {
				mCurrentUPort.close();
				mCurrentUPort = null;
			} catch (MxException e) {
				mLogText.append("Failed to close\n");
			}
		}	
		
		mCloseButton.setEnabled(true);
		mOpenButton.setEnabled(true);
		mWriteButton.setEnabled(false);
		mPropertyButton.setEnabled(false);
		mFlushButton.setEnabled(false);
		mRTSButton.setEnabled(false);
		mDTRButton.setEnabled(false);
	    mBaudRateSpinner.setEnabled(true);
	    mParitySpinner.setEnabled(true);
	    mFlowSpinner.setEnabled(true);
	    mDataBitsSpinner.setEnabled(true);
	    mStopBitsSpinner.setEnabled(true);
    }
    
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
		
		IntentFilter usbFilter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED);
		registerReceiver(mUsbReceiver, usbFilter);

		TextView textVersion = (TextView) findViewById(R.id.text_Version);
		textVersion.setText("MxUPortAPI Demo (Library version: " + Version.getString() + ")");

		mLogText = (EditText) findViewById(R.id.text_log);
		mLogText.setScroller(new Scroller(this));
		mLogText.setVerticalScrollBarEnabled(true);
		mLogText.setFocusable(false); 
		mLogText.setClickable(false);
		
		mWriteEditCtrl = (EditText) findViewById(R.id.edit_write);
		mSetPortNameCtrl = (EditText) findViewById(R.id.edit_set_name);
		
		mOpenButton = (Button) findViewById(R.id.button_open);
		mCloseButton = (Button) findViewById(R.id.button_close);
		mWriteButton = (Button) findViewById(R.id.button_write);
		mPropertyButton = (Button) findViewById(R.id.button_get_property);
		mFlushButton = (Button) findViewById(R.id.button_flush);
		mRTSButton = (Button) findViewById(R.id.button_toggle_rts);
		mDTRButton = (Button) findViewById(R.id.button_toggle_dtr);
		
		mWriteButton.setEnabled(false);
		mPropertyButton.setEnabled(false);
		mFlushButton.setEnabled(false);
		mRTSButton.setEnabled(false);
		mDTRButton.setEnabled(false);
		
		//
		// Port Name spinner
		//
		Spinner spinner = (Spinner) findViewById(R.id.spinner_port_name);
		mPortListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, android.R.id.text1);
		mPortListAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		spinner.setAdapter(mPortListAdapter);
		if( mPortList!=null ){
			for( MxUPort p : mPortList ){
				try {
					mPortListAdapter.add(String.format("(ID: %d) %s", p.getUsbDevice().getDeviceId(), p.getPortName() ));
				} catch (MxException e) {
					Log.e(TAG, "Failed to get device strings");
					e.printStackTrace();
				}
			}
		}
		mPortListAdapter.notifyDataSetChanged();
		
		spinner.setAdapter(mPortListAdapter);
        spinner.setOnItemSelectedListener(
                new OnItemSelectedListener() {
                    public void onItemSelected(
                            AdapterView<?> parent, View view, int position, long id) 
                    {
                    	mPortSelection = position;
                    }
                    public void onNothingSelected(AdapterView<?> parent) {
                    	mPortSelection = -1;
                    }
                });

        // Request permission for UPort devices
        if(0==MxUPortService.requestPermission(this, mUsbManager, ACTION_USB_PERMISSION, 0, 0, mPermissionReceiver)){
			mPortList = MxUPortService.getPortInfoList(mUsbManager);
			
			if( mPortList!=null ){
				mPortListAdapter.clear();
				for( MxUPort p : mPortList ){
					try {
						mPortListAdapter.add(String.format("(ID: %d) %s", p.getUsbDevice().getDeviceId(), p.getPortName() ));
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				mPortListAdapter.notifyDataSetChanged();
			}
			
        }
        

        //
		// Baud rate spinner
		//
		mBaudRateSpinner = (Spinner) findViewById(R.id.spinner_baud_rate);

		mBaudRateAdapter = ArrayAdapter.createFromResource(this,
		        R.array.baud_rate_array, android.R.layout.simple_spinner_item);
		
		mBaudRateAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		mBaudRateSpinner.setAdapter(mBaudRateAdapter);
		mBaudRateSpinner.setSelection(11);
		
        mBaudRateSpinner.setOnItemSelectedListener(
                new OnItemSelectedListener() {
                    public void onItemSelected(
                            AdapterView<?> parent, View view, int position, long id) 
                    {
                    	mBaudRate = Integer.valueOf(mBaudRateAdapter.getItem(position).toString());
                    }
                    public void onNothingSelected(AdapterView<?> parent) {
                    	mBaudRate = -1;
                    }
                });
        
        //
		// Flow Control spinner
        //
        
		mFlowSpinner = (Spinner) findViewById(R.id.spinner_flow_control);

		mFlowControlAdapter = ArrayAdapter.createFromResource(this,
		        R.array.flow_control_array, android.R.layout.simple_spinner_item);
		mFlowControlAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		mFlowSpinner.setAdapter(mFlowControlAdapter);
		mFlowSpinner.setSelection(2);
		
		mFlowSpinner.setOnItemSelectedListener(
                new OnItemSelectedListener() {
                    public void onItemSelected(
                            AdapterView<?> parent, View view, int position, long id) 
                    {
                    	mFlowControl = position;
                    }
                    public void onNothingSelected(AdapterView<?> parent) {
                    	mFlowControl = -1;
                    }
                });
        

        //
		// Data bits spinner
        //
		
		mDataBitsSpinner = (Spinner) findViewById(R.id.spinner_data_bits);

		mDataBitsAdapter = ArrayAdapter.createFromResource(this,
		        R.array.data_bits_array, android.R.layout.simple_spinner_item);
		mDataBitsAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		mDataBitsSpinner.setAdapter(mDataBitsAdapter);
		mDataBitsSpinner.setSelection(3);
		
		mDataBitsSpinner.setOnItemSelectedListener(
                new OnItemSelectedListener() {
                    public void onItemSelected(
                            AdapterView<?> parent, View view, int position, long id) 
                    {
                    	mDataBits = Integer.valueOf(mDataBitsAdapter.getItem(position).toString());
                    }
                    public void onNothingSelected(AdapterView<?> parent) {
                    	mDataBits = -1;
                    }
                });

        //
		// Parity spinner
        //
		
	    mParitySpinner = (Spinner) findViewById(R.id.spinner_parity);

		mParityAdapter = ArrayAdapter.createFromResource(this,
		        R.array.parity_array, android.R.layout.simple_spinner_item);
		mParityAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		mParitySpinner.setAdapter(mParityAdapter);
		mParitySpinner.setSelection(0);
		
		mParitySpinner.setOnItemSelectedListener(
                new OnItemSelectedListener() {
                    public void onItemSelected(
                            AdapterView<?> parent, View view, int position, long id) 
                    {
                    	mParity = position;
                    }
                    public void onNothingSelected(AdapterView<?> parent) {
                    	mParity = -1;
                    }
                });

		//
		// Stop Bits spinner
        //
	    mStopBitsSpinner = (Spinner) findViewById(R.id.spinner_stop_bits);

		mStopBitsAdapter = ArrayAdapter.createFromResource(this,
		        R.array.stop_bits_array, android.R.layout.simple_spinner_item);
		mStopBitsAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		mStopBitsSpinner.setAdapter(mStopBitsAdapter);
		mStopBitsSpinner.setSelection(0);
		
		mStopBitsSpinner.setOnItemSelectedListener(
                new OnItemSelectedListener() {
                    public void onItemSelected(
                            AdapterView<?> parent, View view, int position, long id) 
                    {
                    	mStopBits = Integer.valueOf(mStopBitsAdapter.getItem(position).toString());
                    }
                    public void onNothingSelected(AdapterView<?> parent) {
                    	mDataBits = -1;
                    }
                });
        
        
        mWriteEditCtrl.setText("Click write to send");
        mSetPortNameCtrl.setText("Friendly Name");
        
		mOpenButton.setFocusableInTouchMode(true);
        mOpenButton.requestFocus();		
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
	
	public void finish(){
		if( mCurrentUPort!=null ){
			try {
				mCurrentUPort.close();
			} catch (MxException e) {
			}
		}
		super.finish();
	}

	public void OnClose(View view){
		
		mLogText.append("OnClose\n");
		doClosePort();

	}

	public void OnGetProperty(View view){
		
		if( mCurrentUPort != null ){
			
			int intf = 0;
			int baud = 0;
			IoctlMode mode = null;
			FlowCtrl flow = null;
			ModemStatus modem = null;
			LineError err = null;
			int outQueue = 0;
			int usbReadTimeout;
			int usbWriteTimeout;
			boolean isSet = false;
			
			try {
				mLogText.append("-- Property ---------------------\n");
				
				intf = mCurrentUPort.getInterface();
				if( intf==MxUPort.MODE_RS232 ){
					mLogText.append("Interface: RS232\n");
				} else if( intf==MxUPort.MODE_RS422 || intf==MxUPort.MODE_RS485_4W ){
					mLogText.append("Interface: RS422/RS485_4W\n");
				} else if( intf==MxUPort.MODE_RS485_2W ){
					mLogText.append("Interface: RS485_2W\n");
				}	
				
				baud = mCurrentUPort.getBaud();
				mLogText.append("Baud: "+baud+"   ");
	
				mode = mCurrentUPort.getIoctlMode();
				mLogText.append("Data bits: ");
				switch (mode.dataBits){
				case MxUPort.DATA_BITS_5:
					mLogText.append("5");
					break;
				case MxUPort.DATA_BITS_6:
					mLogText.append("6");
					break;
				case MxUPort.DATA_BITS_7:
					mLogText.append("7");
					break;
				case MxUPort.DATA_BITS_8:
					mLogText.append("8");
					break;
				default:
					mLogText.append("error");
				}
				mLogText.append("   ");
				
				mLogText.append("Parity: ");
				switch (mode.parity){
				case MxUPort.PARITY_NONE:
					mLogText.append("None");
					break;
				case MxUPort.PARITY_ODD:
					mLogText.append("Odd");
					break;
				case MxUPort.PARITY_EVEN:
					mLogText.append("Even");
					break;
				default:
					mLogText.append("error");
				}
				mLogText.append("   ");
	
				mLogText.append("Stop bits: ");
				switch (mode.stopBits){
				case MxUPort.STOP_BITS_1:
					mLogText.append("1");
					break;
				case MxUPort.STOP_BITS_2:
					mLogText.append("2");
					break;
				case MxUPort.STOP_BITS_1_5:
					mLogText.append("1.5");
					break;
				default:
					mLogText.append("error");
				}
				mLogText.append("\n");
				
				isSet = false;
				flow = mCurrentUPort.getFlowCtrl();
				mLogText.append("Flow control: ");
				if( (flow.RtsCts & MxUPort.RTS_FLOW_ENABLE) != 0 ){
					isSet = true;
					mLogText.append("RTS ");
				}
				if( (flow.RtsCts & MxUPort.CTS_FLOW_ENABLE) != 0 ){
					isSet = true;
					mLogText.append("CTS ");
				}
				if( (flow.XonXoff & MxUPort.XON_FLOW_ENABLE) != 0 ){
					isSet = true;
					mLogText.append("XON ");
				}
				if( (flow.XonXoff & MxUPort.XOFF_FLOW_ENABLE) != 0 ){
					isSet = true;
					mLogText.append("XOFF ");
				}
				if( (flow.DtrDsr & MxUPort.DTR_FLOW_ENABLE) != 0 ){
					isSet = true;
					mLogText.append("DTR ");
				}
				if( (flow.DtrDsr & MxUPort.DSR_FLOW_ENABLE) != 0 ){
					isSet = true;
					mLogText.append("DSR ");
				}
				if( !isSet ){
					mLogText.append("No flow control");
				}
				mLogText.append("\n");
				
				isSet = false;
				modem = mCurrentUPort.getModemStatus();
				mLogText.append("Modem status: ");
				if( modem.CTS == MxUPort.CTS_ON ){
					isSet = true;
					mLogText.append("CTS ");
				}
				if( modem.DSR == MxUPort.DSR_ON ){
					isSet = true;
					mLogText.append("DSR ");
				}
				if( modem.DCD == MxUPort.DCD_ON ){
					isSet = true;
					mLogText.append("DCD ");
				}
				if( modem.RI == MxUPort.RI_ON ){
					isSet = true;
					mLogText.append("RI");
				}
				if( !isSet ){
					mLogText.append("----");
				}
				mLogText.append("\n");
				
				outQueue = mCurrentUPort.getOQueue();
				mLogText.append("Out queue: "+outQueue+" (bytes)   ");
				
				usbReadTimeout = mCurrentUPort.getUsbReadTimeout();
				mLogText.append("USB Read timeout: "+usbReadTimeout+" (ms)   ");
				
				usbWriteTimeout = mCurrentUPort.getUsbWriteTimeout();
				mLogText.append("USB Write timeout: "+usbWriteTimeout+" (ms)\n");
	
				isSet = false;
				err = mCurrentUPort.getLineStatus();
				mLogText.append("Line status: ");
				if( err.overrun_error == MxUPort.LINE_ERROR ){
					isSet = true;
					mLogText.append("OVERRUN ");
				}
				if( err.framing_error == MxUPort.LINE_ERROR ){
					isSet = true;
					mLogText.append("FRAMING ");
				}
				if( err.break_error == MxUPort.LINE_ERROR ){
					isSet = true;
					mLogText.append("BREAK ");
				}
				if( err.parity_error == MxUPort.LINE_ERROR ){
					isSet = true;
					mLogText.append("PARITY");
				}
				if( !isSet ){
					mLogText.append("No error");
				}
				mLogText.append("\n");
				
				mLogText.append("-- End of property --------------\n");
				
			} catch (MxException e) {
				mLogText.append("Failed to get property\n");
			}
			
		} else {
			mLogText.append("port is not opened.\n");
		}	
	}

	public void OnOpen(View view){
		mLogText.setText("");
		mLogText.append("OnOpen\n");
		
		if( mPortList==null ){
			mLogText.append("Device not found\n");
			return;
		}
		
		IoctlMode mode = new IoctlMode();
		mode.baudRate = mBaudRate;
		
		switch(mDataBits){
		case 5:
			mode.dataBits = MxUPort.DATA_BITS_5;
			break;
		case 6:
			mode.dataBits = MxUPort.DATA_BITS_6;
			break;
		case 7:
			mode.dataBits = MxUPort.DATA_BITS_7;
			break;
		case 8:
		default:
			mode.dataBits = MxUPort.DATA_BITS_8;
			break;
		}
		
		switch(mParity){
		case 0:
		default:
			mode.parity = MxUPort.PARITY_NONE;
			break;
		case 1:
			mode.parity = MxUPort.PARITY_EVEN;
			break;
		case 2:
			mode.parity = MxUPort.PARITY_ODD;
			break;
		}
		
		switch(mStopBits){
		case 1:
		default:
			mode.stopBits = MxUPort.STOP_BITS_1;
			break;
		case 2:
			mode.stopBits = MxUPort.STOP_BITS_2;
			break;
		}

		FlowCtrl flow = new FlowCtrl();

		switch(mFlowControl){
		case 0:
		default:
			flow.RtsCts = MxUPort.RTSCTS_FLOW_ENABLE;
			break;
		case 1:
			flow.XonXoff = MxUPort.XONXOFF_FLOW_ENABLE;
			break;
		case 2:
			flow.RtsCts &= ~(MxUPort.RTSCTS_FLOW_ENABLE);
			flow.XonXoff &= ~(MxUPort.XONXOFF_FLOW_ENABLE);
			break;
		}
		
		mCurrentUPort = mPortList.get(mPortSelection);
		
		try {
			mCurrentUPort.open();
			int pid = mCurrentUPort.getUsbDevice().getProductId();
			
			if( pid==MxUPortService.DeviceID.UPORT1130.getProductId() ||
				pid==MxUPortService.DeviceID.UPORT1130I.getProductId() )
			{
				mCurrentUPort.setInterface(MxUPort.MODE_RS422);
			} else {
				mCurrentUPort.setInterface(MxUPort.MODE_RS232);
			}
			
			mCurrentUPort.setFlowCtrl(flow);
			mCurrentUPort.setIoctlMode(mode);
			
			if( (flow.RtsCts & MxUPort.RTS_FLOW_ENABLE)==0 ){
				mCurrentUPort.setRTS(mRtsEnable);
			}
			if( (flow.DtrDsr & MxUPort.DTR_FLOW_ENABLE)==0 ){
				mCurrentUPort.setDTR(mDtrEnable);
			}

		} catch (MxException e1) {
			mLogText.append("Failed to open\n");
			mLogText.append(e1.getMessage());
			
			try {
				mCurrentUPort.close();
			} catch (MxException e) {
			}
			mCurrentUPort = null;
			return;
		}

		mExitThread = false;
		
		Thread threadRead = new Thread()
		{
    	    @Override
    	    public void run() {
    	    	
    	    	final int RXBUF_SIZE = 20;
		    	
	            byte[] dest = new byte[RXBUF_SIZE];
	    			
    			int length = 0;    			

    			while( mExitThread==false ){
				
    				try {
    					Arrays.fill(dest, (byte) 0);
						length = mCurrentUPort.read(dest, RXBUF_SIZE, 50);
								
						if( length > 0 ){
							synchronized(mReadTextLock){
								mReadTextList.add(new ReadText(dest, length));
								mReadTextLock.notifyAll();
							}
						} else if( length<0 ) {
							break;
						}
		            } catch (MxException e){
		            	Log.e(TAG, "Read data failed.");
		            	return;
		            }
    			}
    	    }
		};
		threadRead.start();

		Thread threadShow = new Thread()
		{
    	    @Override
    	    public void run() {
    	    	
    			while( mExitThread==false ){
    				synchronized(mReadTextLock){
    					if( !mReadTextList.isEmpty() ){
	      					runOnUiThread(mReadTextList.remove(0));
	    				}
       					try {
    						mReadTextLock.wait(1000);
    					} catch (InterruptedException e) {}
   					}
    			}
    	    }
		};
		threadShow.start();

		
		mLogText.append("Port opened\n");
		
    	if( mOpenButton.isEnabled() ){
    		mOpenButton.setEnabled(false);	  
    		mWriteButton.setEnabled(true);
    		mPropertyButton.setEnabled(true);
    		mFlushButton.setEnabled(true);
    		mRTSButton.setEnabled(true);
    		mDTRButton.setEnabled(true);    
    	    mBaudRateSpinner.setEnabled(false);
    	    mParitySpinner.setEnabled(false);
    	    mFlowSpinner.setEnabled(false);
    	    mDataBitsSpinner.setEnabled(false);
    	    mStopBitsSpinner.setEnabled(false);
    	}

	}
	
	public void OnFlush(View view){
		
		if( mPortList==null ){
			mLogText.append("Device not found\n");
			return;
		}
	
		MxUPort p = mPortList.get(mPortSelection);
		
		if( p != null ){
			try{
				p.flush(MxUPort.FLUSH_INPUT|MxUPort.FLUSH_OUTPUT);
			} catch (MxException e) {
				mLogText.append("Failed to flush device\n");
			}
			mLogText.append("Port is flush.\n");
		}		
	}

	public void OnScan(View view){
		
		mPortListAdapter.clear();
        if(0==MxUPortService.requestPermission(this, mUsbManager, ACTION_USB_PERMISSION, 0, 0, mPermissionReceiver)){
			mPortList = MxUPortService.getPortInfoList(mUsbManager);
			
			if( mPortList!=null ){
				mPortListAdapter.clear();
				for( MxUPort p : mPortList ){
					try {
						mPortListAdapter.add(String.format("(ID: %d) %s", p.getUsbDevice().getDeviceId(), p.getPortName() ));
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				mPortListAdapter.notifyDataSetChanged();
			}
			
        }

		
	}
	
	public void OnToggleDtr(View view){
		if( mCurrentUPort != null ){
			try {
				if( mDtrEnable==MxUPort.DTR_ON ){
					mDtrEnable=MxUPort.DTR_OFF;
					mLogText.append("Set DTR OFF");
				} else {
					mDtrEnable=MxUPort.DTR_ON;
					mLogText.append("Set DTR ON");
				}
				mCurrentUPort.setDTR(mDtrEnable);
	
			} catch (MxException e) {
				mLogText.append(e.getMessage());
				return;
			}
			mLogText.append(" successfully.\n");
		} else {
			mLogText.append("port is not opened.\n");
		}
	}

	public void OnToggleRts(View view){
		if( mCurrentUPort != null ){
			try {
				if( mRtsEnable==MxUPort.RTS_ON ){
					mRtsEnable=MxUPort.RTS_OFF;
					mLogText.append("Set RTS OFF");
				} else {
					mRtsEnable=MxUPort.RTS_ON;
					mLogText.append("Set RTS ON");
				}
				mCurrentUPort.setRTS(mRtsEnable);
	
			} catch (MxException e) {
				mLogText.append(e.getMessage());
				return;
			}
			mLogText.append(" successfully.\n");
		} else {
			mLogText.append("port is not opened.\n");
		}		
	}

	public void OnWrite(View view){

		
		int len = 0;
		byte[] buf = mWriteEditCtrl.getText().toString().getBytes();
		
		if( mCurrentUPort != null ){
			mLogText.append("OnWrite\n");

			try {
				len = mCurrentUPort.write(buf,  buf.length);
			} catch (MxException e) {
				mLogText.append("Failed to write\n");
			}
			mLogText.append(String.format("%d bytes are written.\n", len));
		} else {
			mLogText.append("port is not opened.\n");
		}
	}
	
	public void OnSetPortName(View view){
		
		if( mPortList==null ){
			mLogText.append("Device not found\n");
			return;
		}
	
		MxUPort p = mPortList.get(mPortSelection);
		String str = mSetPortNameCtrl.getText().toString();
		
		if( p != null ){
			try{
				p.setPortName(str);
			} catch (MxException e) {
				if( e.getErrorCode()==ErrorCode.InvalidParameter ){
					mLogText.append("Port name is invalid.");
				} else {
					mLogText.append("Failed to set port name\n");
				}
				return;
			}
			mLogText.append("Port name is changed.\n");
		}
		
		mPortListAdapter.clear();
		MxUPortService.requestPermission(this, mUsbManager, ACTION_USB_PERMISSION, 0, 0, mPermissionReceiver);
	}	

	
	private static final String ACTION_USB_PERMISSION =
		    "com.moxa.mxuportapidemo.USB_PERMISSION";
	
	
	private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			
			if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
				
                UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                
                boolean isDetached = false;
                int deviceId = device.getDeviceId();
                
                for( MxUPort p : mPortList ){
                	if( p.getUsbDevice().getDeviceId() == deviceId ){
                		isDetached = true;
                	}
                }

                if( mCurrentUPort!=null ){
                    if( mCurrentUPort.getUsbDevice().getDeviceId()==deviceId ){
                    	doClosePort();
                    }
                }
                
                if( isDetached ){
                    Log.d(TAG, "USB device detached!");
            		mPortListAdapter.clear();
            		MxUPortService.requestPermission(context, mUsbManager, ACTION_USB_PERMISSION, 0, 0, mPermissionReceiver);
                }
                
                
            }			
		}
		
	};
	
	private final BroadcastReceiver mPermissionReceiver = new BroadcastReceiver() {
		
		public void onReceive(Context context, Intent intent) {
			
			String action = intent.getAction();
			
			if (ACTION_USB_PERMISSION.equals(action)) {
				
				synchronized (this) {
					UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
				
					if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
						if(device != null){
							Log.d(TAG, "The permission of device PID: "+device.getVendorId()+" is granted.");
							
							mPortList = MxUPortService.getPortInfoList(mUsbManager);
							
							if( mPortList!=null ){
								mPortListAdapter.clear();
								for( MxUPort p : mPortList ){
									try {
										if( !p.hasUsbPermission() ){
											Thread.sleep(500);
											MxUPortService.requestPermission(context, mUsbManager, ACTION_USB_PERMISSION, 0, 0, mPermissionReceiver);
											break;
										}
										mPortListAdapter.add(String.format("(ID: %d) %s", p.getUsbDevice().getDeviceId(), p.getPortName() ));
									} catch (Exception e) {
										e.printStackTrace();
									}
								}
								mPortListAdapter.notifyDataSetChanged();
							}
							
						}
					}
				}
				
			}
		}
	};
	
}
