지금까지 블루투스를 활성화 하고 기기 검색을 하는 단계까지 진행하였다.


이전 글 : 블루투스 활성화 글 보기블루투스 기기 검색하기 글 보기


저번 프로젝트에 이어 블루투스 연결하는 단계를 포스팅 하겠다.


검색한 기기에 연결하기 위해서는 ConnectThread와 ConnectedThread에 대해서 알고 있어야 한다.

BluetoothService.java 파일에 ConnectThread와 ConnectedThread 클래스를 내부 클래스로 삽입해준다.


1. ConnectThread


BluetoothService.java

public class BluetoothService {
	... // 이전 부분 생략

	// RFCOMM Protocol
	private static final UUID MY_UUID = 
		UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
	
	private BluetoothAdapter btAdapter;
	
	private ConnectThread mConnectThread;
	private ConnectedThread mConnectedThread;

	... // 이전 부분 생략
		
	private class ConnectThread extends Thread {
		private final BluetoothSocket mmSocket;
		private final BluetoothDevice mmDevice;

		public ConnectThread(BluetoothDevice device) {
			mmDevice = device;
			BluetoothSocket tmp = null;
			
			// 디바이스 정보를 얻어서 BluetoothSocket 생성
			try {
                tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
            } catch (IOException e) {
                Log.e(TAG, "create() failed", e);
            }
			mmSocket = tmp;
		}

		public void run() {
			Log.i(TAG, "BEGIN mConnectThread");
			setName("ConnectThread");
			
			// 연결을 시도하기 전에는 항상 기기 검색을 중지한다.
			// 기기 검색이 계속되면 연결속도가 느려지기 때문이다.
			btAdapter.cancelDiscovery();

			// BluetoothSocket 연결 시도
			try {
				// BluetoothSocket 연결 시도에 대한 return 값은 succes 또는 exception이다.
				mmSocket.connect();
				Log.d(TAG, "Connect Success");
				
			} catch (IOException e) {
				connectionFailed();		// 연결 실패시 불러오는 메소드
				Log.d(TAG, "Connect Fail");
				
				// socket을 닫는다.
				try {
					mmSocket.close();
				} catch (IOException e2) {
					Log.e(TAG,
							"unable to close() socket during connection failure",
							e2);
				}
				// 연결중? 혹은 연결 대기상태인 메소드를 호출한다.
				BluetoothService.this.start();
				return;
			}

			// ConnectThread 클래스를 reset한다.
			synchronized (BluetoothService.this) {
				mConnectThread = null;
			}

			// ConnectThread를 시작한다.
			connected(mmSocket, mmDevice);
		}

		public void cancel() {
			try {
				mmSocket.close();
			} catch (IOException e) {
				Log.e(TAG, "close() of connect socket failed", e);
			}
		}
	}
}


여기서 UUID라는 변수가 있는데 이것은 Bluetooth 통신 프로토콜이다. 블루투스 통신을 할 때 그에 맞는 프로토콜로 통신을 해 주어야 한다. 간단한 예로 블루투스 기능이 지원되는 이어폰과의 통신을 원한다면 그에 맞는 프로토콜을 사용하여야 하고, 스마트폰 끼리의 블루투스 통신은 또 그에 맞는 프로토콜을 사용해야 한다. 

지금 위에서 사용한 프로토콜은 아마 스마트폰끼리의 블루투스 통신을 하는데 사용하는 프로토콜일 것이다.


블루투스 프로토콜 종류 보기 - [안드로이드] 블루투스 프로토콜 UUID 리스트


2. ConnectedThread


위에서(ConnectThread) 다음단계가 ConnectedThread이다. 위 단계에서는 연결을 하는 중간단계 까지라고 생각하고, 이번 단계는 연결을 완료하는 단계라고 생각하면 될 것 같다. 위와 동일하게 BluetoothService 클래스에 내부 클래스로 정의한다.


BluetoothService.java

public class BluetoothService {
	... // 이 전 부분 생략
	
	private BluetoothAdapter btAdapter;
	
	private Activity mActivity;
	private Handler mHandler;

	private ConnectThread mConnectThread; // 변수명 다시
	private ConnectedThread mConnectedThread; // 변수명 다시
	
	... // 이 전 부분 생략
	
    private class ConnectedThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final InputStream mmInStream;
        private final OutputStream mmOutStream;

        public ConnectedThread(BluetoothSocket socket) {
            Log.d(TAG, "create ConnectedThread");
            mmSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            // BluetoothSocket의 inputstream 과 outputstream을 얻는다.
            try {
                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();
            } catch (IOException e) {
                Log.e(TAG, "temp sockets not created", e);
            }

            mmInStream = tmpIn;
            mmOutStream = tmpOut;
        }

        public void run() {
            Log.i(TAG, "BEGIN mConnectedThread");
            byte[] buffer = new byte[1024];
            int bytes;

            // Keep listening to the InputStream while connected
            while (true) {
                try {
                    // InputStream으로부터 값을 받는 읽는 부분(값을 받는다)
                    bytes = mmInStream.read(buffer);

                } catch (IOException e) {
                    Log.e(TAG, "disconnected", e);
                    connectionLost();
                    break;
                }
            }
        }

        /**
         * Write to the connected OutStream.
         * @param buffer  The bytes to write
         */
        public void write(byte[] buffer) {
            try {
            	// 값을 쓰는 부분(값을 보낸다)
                mmOutStream.write(buffer);

            } catch (IOException e) {
                Log.e(TAG, "Exception during write", e);
            }
        }

        public void cancel() {
            try {
                mmSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "close() of connect socket failed", e);
            }
        }
    }
}



3. 마무리 작업


지금까지 잘 따라했다면 몇 가지 빨간줄이 있을 것이다. 이 빨간줄을 지워보자

기본 베이스는 처음에 말했듯이 안드로이드 기본 예제인 BluetoothChat이다.

BluetoothChat에서 다음과 같은 메소드를 모두 복사해서 BluetoothService.java에 붙여넣어 빨간줄을 없애보자


BluetoothService.java

public class BluetoothService {
	... // 이 전과 동일
	private int mState;

	// 상태를 나타내는 상태 변수
	private static final int STATE_NONE = 0; // we're doing nothing
	private static final int STATE_LISTEN = 1; // now listening for incoming connections
	private static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
	private static final int STATE_CONNECTED = 3; // now connected to a remote device

	... // 이 전과 동일

	// Bluetooth 상태 set
	private synchronized void setState(int state) {
		Log.d(TAG, "setState() " + mState + " -> " + state);
		mState = state;
	}

	// Bluetooth 상태 get
	public synchronized int getState() {
		return mState;
	}

	public synchronized void start() {
		Log.d(TAG, "start");

		// Cancel any thread attempting to make a connection
		if (mConnectThread == null) {

		} else {
			mConnectThread.cancel();
			mConnectThread = null;
		}

		// Cancel any thread currently running a connection
		if (mConnectedThread == null) {

		} else {
			mConnectedThread.cancel();
			mConnectedThread = null;
		}
	}

	// ConnectThread 초기화 device의 모든 연결 제거
	public synchronized void connect(BluetoothDevice device) {
		Log.d(TAG, "connect to: " + device);

		// Cancel any thread attempting to make a connection
		if (mState == STATE_CONNECTING) {
			if (mConnectThread == null) {

			} else {
				mConnectThread.cancel();
				mConnectThread = null;
			}
		}

		// Cancel any thread currently running a connection
		if (mConnectedThread == null) {

		} else {
			mConnectedThread.cancel();
			mConnectedThread = null;
		}

		// Start the thread to connect with the given device
		mConnectThread = new ConnectThread(device);

		mConnectThread.start();
		setState(STATE_CONNECTING);
	}

	// ConnectedThread 초기화
	public synchronized void connected(BluetoothSocket socket,
			BluetoothDevice device) {
		Log.d(TAG, "connected");

		// Cancel the thread that completed the connection
		if (mConnectThread == null) {

		} else {
			mConnectThread.cancel();
			mConnectThread = null;
		}

		// Cancel any thread currently running a connection
		if (mConnectedThread == null) {

		} else {
			mConnectedThread.cancel();
			mConnectedThread = null;
		}

		// Start the thread to manage the connection and perform transmissions
		mConnectedThread = new ConnectedThread(socket);
		mConnectedThread.start();

		setState(STATE_CONNECTED);
	}

	// 모든 thread stop
	public synchronized void stop() {
		Log.d(TAG, "stop");

		if (mConnectThread != null) {
			mConnectThread.cancel();
			mConnectThread = null;
		}

		if (mConnectedThread != null) {
			mConnectedThread.cancel();
			mConnectedThread = null;
		}

		setState(STATE_NONE);
	}

	// 값을 쓰는 부분(보내는 부분)
	public void write(byte[] out) { // Create temporary object
		ConnectedThread r; // Synchronize a copy of the ConnectedThread
		synchronized (this) {
			if (mState != STATE_CONNECTED)
				return;
			r = mConnectedThread;
		} // Perform the write unsynchronized r.write(out); }
	}

	// 연결 실패했을때
	private void connectionFailed() {
		setState(STATE_LISTEN);
	}

	// 연결을 잃었을 때 
	private void connectionLost() {
		setState(STATE_LISTEN);

	}

	private class ConnectThread extends Thread {
		... 
	}

	private class ConnectedThread extends Thread {
		...
	}
}


EX_Bluetooth.zip



마지막에 설명을 쫌 대강대강 하고 넘어간 부분이 많은데, 일단은 현재까지의 프로젝트를 압축파일로 올리겠다.

이후 시간이 된다면 스마트폰 끼리의 블루투스 예제를 주석을 달아서 올리도록 하겠다. 

또한, 글쓴이는 임베디드 보드(동글)과 통신을 하였는데 이 부분에 대해서 궁금하신 분이 많다면 서둘러 예제 프로젝트를 올리도록 하겠다.

+ Recent posts