티스토리 뷰

요즘들어 안드로이드를 이용하여 하드웨어와 통신하는 사례가 부쩍 늘고 있다. 예를 들어 릴레이 도오락을 열거나, 문서를 프린트하거나 등... 하지만 인터넷에서 찾아볼수 있는 자료는 거의 대부분 쓰잘데기 없는 것들이여서 나름대로 여기에 정리 해 본다.

시리얼 통신의 개념은 아주 간단하다, 즉 (bit) 비트단위로 데이터를 발송하거나 전송하는 방식을 말한다. 비록 (byte) 바이트 단위로 통신하는 병열통신 보다는 느리지만 시리얼 통신은 한가닥의 선으로 데이터를 전송하는 동시에 다른 한가닥의 선으로는 데이터를 받을 수 있다. 이런 장점 때문에 구현이 간단 할 뿐만 아니라 통신거리도 비교적 길다.

Widnows, Linux, 혹은 Android 운영체제든 시리얼통신의 프로그래밍 순서는 아래와 같다.

1. 시리얼포트를 연다
2. 시리얼포트를 셋팅한다
3. 시리얼포트를 사용하여 읽거나 쓴다
4. 시리얼포트를 닫는다.

여기서는 구글의 오픈소스인 android-serialport-api를 이용할 것이며, 이 오픈 소스는 Android에서 jni를 이용하여 직접적으로 시리얼 장비에 연결하여 읽고/쓸수 있는 오픈 소스이다. 때문에 NDK에 대한 특별한 이해가 없어도 되며 여기에서도 자세한 내용은 다룰 생각이 없다.

1. android-serialport-api 간단한 소개

다운로드: https://github.com/cepr/android-serialport-api
android-serialport-api 에는 두개의 중요한 jni폴더와 .so파일이 있다.

 SerialPort

 시리얼포트의 객체를 가져오는 클래스(입출력에 필요함)

 SerialPortFinder

하드웨어의 통신가능한 포트 주소를 가져오는 클래스

2. android-serialport-api 포팅

여기에서는 Android Studio 기준으로 설명  것이다. 만약 Eclipse를 쓰는 사람들은 바로 프로젝트를 Import 하면 된다.

1) 새 Android 프로젝트를 하나 만든다. src/main/java 아래에 android_serialport_api라는 폴더를 하나 만들고 C파일의 연결클래스인 java 클래스 파일(즉 처음에 설명 하였던 SerialPort 와 SerialPortFinder)들을 android_serialport_api 에 넣는다. 여기에서 중요한건 패키이지 명은 반드위 android_serialport_api라고 해야 한다는 것이다. 그 이유는 JNI를 좀 해본 사람은 알겠지만 C로 다이나믹 라이브러리를 작성할때 함수의 이름은 그 함수를 호출하는 클래스가 속해 있는 패키이지 이름과 연관되어 있기 때문이다. 만약 패키이지 이름과 C로 작성한 파일의 함수 이름이 서로 틀리면 C의 함수를 호출 할 수 다.

2) src/main 아래 jni, jinLibs 폴더를 하나 만든다. 그리고 관련 파일들을 카피해서 폴더에 각각 넣는다.  관련 파일을 폴더에 넣었으면 Build/Make Project 를 해서 컴파일 한다. 여기까지 C 라이브러리 불러오는 작업은 끝난 것이다.
* 주의: 컴파일 하는 과정에서 에러가 날수 있다. 그건 컴파일 환경을 설정 해 주지 않아서 인데 아래와 같은 방법을 환경 설정을 해주면 된다.
        1. 프로젝트 이름에서 마우스 오른쪽 버튼을 클릭한다음 Link C++ Project With Gradle이라는 항목을 선택한다.
        2. 드롭다운 메뉴에서 CMake 혹은 ndk-build를 선택한다.
            a. 만약 CMake를 선택하면 CMakeList.txt 파일 경로를 선택한다.
            b. 만약 ndk-build른 선택하면 Android.mk 파일 경로를 선택한다.

3) 시리얼포트로 통신하기

1) 시리얼포트의 하드웨어 주소와 baudrate 속성을 설정할 차례이다. 나같은 경우는 일단 SerialPortUtil이라는 클래스를 하나 만들어서 사용하고 있다. (시리얼 포트를 여는 클래스)

public class SerialPortUtil {
SerialPort mSerialPort;
OutputStream mOutputStream;
InputStream mInputStream;

public SerialPortUtil() {
if (mSerialPort == null) {
String path = "dev/ttymxc4";
int baudrate = 57600;
try{
mSerialPort = new SerialPort(new File(path), baudrate, 0);
mOutputStream = mSerialPort.getOutputStream();
mInputStream = mSerialPort.getInputStream();
} catch (IOException e) {

}
}
} }

2) 데이터 보내기(명령어 발송)

public void sendDate(byte[] writeBytes)
{
try {
if (mOutputStream != null) {
mOutputStream.write(writeBytes);
}
} catch (IOException e) {

}
}

3) 데이터 받기(응답 받기)

public String readData() {
String readDatas = null;
for (int i = 0; i < 10; i++)
{
try {
if (mInputStream != null) {
byte[] buffer = new byte[7];
int size = mInputStream.read(buffer);
if (size > 0)
{
//읽어드릴 응답이 있음
//아래에서 데이터 처리
readDatas = String.format("%02x", buffer);
break;
}else {
Thread.sleep(2000); //2초후 다시 버퍼를 검사한다.
}
}
if(i==9){
break;
}
} catch (IOException e) {

} catch (InterruptedException e) {

}
}
return readDatas;
}

설명: mInputStream.read(buffer) 함수는 메인스레드를 블록 시킬수 있다. 만약 리턴 값이 없으면 어플리케이션이 블록되는 현상이 발생할수 있다. 여기서는 간단한 설명 때문에 따로 스레드를 쓰지 않았지만 만약 실제 상황에서 사용할때는 반드시 새로운 스레드를 생성하여 값을 읽어 드려야 한다.

4) 시리얼 포트 닫기

public void closeSerialPort() {
if (mSerialPort != null)
{
mSerialPort.close();
mSerialPort = null;
}
}

여기까지 하면 모든 사용에 필요한 함수는 만들어 졌고, 각자 어플린케이션의 디자인 패턴에 따라 위 함수들을 최적화화여 사용하면 된다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함