레이블이 codewalker인 게시물을 표시합니다. 모든 게시물 표시
레이블이 codewalker인 게시물을 표시합니다. 모든 게시물 표시

2010년 10월 5일 화요일

android JNI을 이용하여 serial 읽어 오기

http://developer.android.com/sdk/ndk/index.html

위에 홈페이지에서 ndk를 다운 받고 적당한 디렉토리에 압축을 푼다.

eclipse에서 프로젝트를 하나 생성한다.

프로젝트 생성시 반드시 minSdkVersion="3"을 추가 해야 한다.

AndroidManifest.xml에 추가한다.

project 폴더에 jni 폴더를 만들다.

ndk/sample/ 폴더에 예제를 참조 하여 Android.mk를 생성한다.

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := gps_serial
LOCAL_SRC_FILES := gps_serial.c \
jni_serial.c

LOCAL_LDLIBS := -ldl -llog

include $(BUILD_SHARED_LIBRARY)



jni 폴더에 소스를 생성한다.

gps serial를 읽어 오는 gps_serial.h/c를 생성한다.

//---------------gps_serial.h-----------------------//
#ifndef GPS_SERIAL_H
#define GPS_SERIAL_H

char* read_serial();

#endif //GPS_SERIAL_H



//---------------gps_serial.c-----------------------//
#include
#include
#include
#include
#include
#include

#define GPS_SERIAL_NODE "/dev/ttyACM0"
#define READ_COUNT 256
#define LOG_TAG "GPS Serial"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)

int fd = -1;
char buf[READ_COUNT];

int openGPS()
{
LOGI("oepnGPS()");

if (fd = open(GPS_SERIAL_NODE, O_RDONLY) >= 0) {
return fd;
} else {
LOGI("failed to oepn!");
return fd;
}
}

void closeGPS()
{
LOGI("closeGPS()");

if (fd)
close(fd);

fd = -1;
}

char* read_serial()
{
int read_count = 0;
int idx = 0;

memset(buf, 0x00, READ_COUNT);

if (fd == -1)
goto out;

read_count = read(fd, buf, READ_COUNT);
LOGI("count %d", read_count);
LOGI("%s", buf);

LOGI("read success!!");

out:
return buf;
}

여기까지는 일반적인 linux 프로그램이다. 단 printf로 메세지를 확인 할 수 없기 때문에 __android_log_print()를 이용하여 log를 확인 해야 한다.

그리고 java와 c library를 연결 할 jni 함수를 만든다.

//---------------jni_serial.c-----------------------/

#include
#include

#include

void Java_com_hardkernel_gpsserial_GPSSerialActivity_openGPS(JNIEnv* env, jobject obj)
{
openGPS();
}

jstring Java_com_hardkernel_gpsserial_GPSSerialActivity_readGPS(JNIEnv* env, jobject obj)
{
return (*env)->NewStringUTF(env, read_serial());
}

void Java_com_hardkernel_gpsserial_GPSSerialActivity_closeGPS(JNIEnv* env, jobject obj)
{
closeGPS();
}

JNI 함수의 이름 규칙은 Java_ 이후에 package name 그리고 jni를 호출 할 class 이름 그리고 함수 이름을 붙여 주면 됩니다.

Java_com_hardkernel_gpsserial_GPSSerialActivity_openGPS
_____패키지이름_______________class 이름_______함수 이름

이제 ndk를 이용하여 build를 해 보자.

jni 폴더에서 [android-ndk가 설치된 폴더]/ndk-build 명령으로 build를 한다.
하고 나면 아래의 그림과 같이 libs 폴더가 생성된다.


//---------------GPSSerialActivity.java-----------------------/
package com.hardkernel.gpsserial;

import com.hardkernel.gpsserial.R;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.widget.TextView;

public class GPSSerialActivity extends Activity {
private TextView mTv;
private Thread mReadThread = null;
private String mString;
boolean mRunning = false;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTv = (TextView)findViewById(R.id.gps_textview);
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
if (mReadThread != null && mReadThread.isAlive()) {
Log.w("codewalker", "onPause()");
mRunning = false;
mReadThread = null;
}
closeGPS();
}

@Override
protected void onResume() {
// TODO Auto-generated method stub
Log.w("codewalker", "onResume()");
super.onResume();
openGPS();
if (mReadThread == null) {
mRunning = true;
mReadThread = new Thread(new Runnable() {
public void run() {
while (mRunning) {
try {
Thread.sleep(500);
} catch (InterruptedException ignore) {
}
mString = readGPS();
mHandler.sendMessage(mHandler.obtainMessage());
}
}
});
mReadThread.start();
}
}

@Override
protected void onDestroy() {
if (mReadThread != null && mReadThread.isAlive())
mReadThread.destroy();
// TODO Auto-generated method stub
super.onDestroy();
}
Handler mHandler = new Handler()
{
public void handleMessage(android.os.Message msg)
{
mTv.setText(mString);
};
};

public native String readGPS();
public native void openGPS();
public native void closeGPS();

static {
System.loadLibrary("gps_serial");
}
}

jni 함수를 위와 같이 등록해 주고 load해 주는 코드를 추가 한다.

2010년 8월 18일 수요일

odroid에 T-Login(LM-629HUL) 사용하기

이전에 HSDPA USB Modem(LM-629HUL )을 linux에서 사용하기 위한 내용을 posting 하였습니다.
linux에 먼저 작업한 이유는 odroid-t에 t-login을 사용하기 위해서 입니다.

그래서 이번 내용은 이전에 올렸던 linux 작업했던 내용을 이어서 android에 HSDPA USB Modem porting 방법을 posting합니다.

x86 usb-modeswitch는 libusb-0.1 버전을 사용하였습니다.
하지만 libusb android를 검색하면 libusb-1.0 버전이 있습니다.
그리고 libusb-1.0에 libusb-0.1버전을 사용할 수 있는 libusb-compat가 있습니다.
둘다 android용으로 library가 존재 합니다.
하지만 external에 넣고 빌드 하여 libusb.so와 libusb-compat.so를 만들어지만 dynamic link가 되지 않아서 configure에 --enable-static을 둘다 주고 usb_modeswitch도 static으로 만듭니다.
usbutils 역시 동일하게 static으로 만들면 lsusb를 통하여 usb mode switch가 되었는지 확인이 가능합니다.

여기서부터 추가
external 밑에 아래 세 폴더를 복사 합니다.
monaka-libusb-android-b35de21
monaka-libusb-compat-android-85dc44d
usb-modeswitch-1.1.3

monaka는 Android.mk가 있습니다.

usb-modeswitch-1.1.3에 Android.mk는 아래와 같습니다.

1 ifeq ($(TARGET_ARCH),arm)
2
3 LOCAL_PATH:= $(call my-dir)
4 include $(CLEAR_VARS)
5
6 LOCAL_SRC_FILES:= \
7 usb_modeswitch.c
8
9 LOCAL_SHARED_LIBRARIES := \
10 libusb-compat libusb
11
12 LOCAL_C_INCLUDES := \
13 $(LOCAL_PATH)/include
14
15 LOCAL_CFLAGS := \
16 -Iexternal/monaka-libusb-compat-android-85dc44d/libusb -pthread -rt
17
18 LOCAL_MODULE:= usb_modeswitch
19
20 include $(BUILD_EXECUTABLE)
21
22 endif

이렇게 추가하면 odroidt-img/system/bin/usb_modeswitch와 odroidt-img/system/lib/libusb.so, libusb-compat.so가 생깁니다.

그리고 추가로 external/monaka-libusb-android-b35de21/examples을 컴파일 하면 lsusb가 생깁니다.
Android.mk는 아래와 같습니다.

1 ifeq ($(TARGET_ARCH),arm)
2
3 LOCAL_PATH:= $(call my-dir)
4
5 include $(CLEAR_VARS)
6
7 LOCAL_SRC_FILES:= \
8 lsusb.c
9
10 LOCAL_C_INCLUDES += $(LOCAL_PATH)/android \
11 external/monaka-libusb-android-b35de21
12
13 LOCAL_SHARED_LIBRARIES := \
14 libusb
15
16 LOCAL_CFLAGS := \
17 -pthread -rt
18
19 LOCAL_MODULE:= lsusb
20
21 include $(BUILD_EXECUTABLE)
22
23 endif

이렇게 위에서 언급한 static문제는 해결 되었습니다.
추가 끝

다음 단계로 커널에 usb file system이 올라 가야 합니다. kernel에 usb file system을 추가 하시고
odroid-t는 ramdisk를 사용함으로 vendor/sec/android/conf/init_ramdisk.rc 파일에 usbfs를 mount하도록 추가 합니다.

mount usbfs none /proc/bus/usb

다음 부터는 아래 주소에 있는 x86 emulator에서 HSDPA를 연결한 내용을 참고하였습니다.

내용을 간략하게 설명하면 host linux에 modem을 연결하면 ttyUSB가 생성되고 여기서 command port인 ttyUSB3을 android의 ttyS1으로 연결한다는 내용입니다.

vendor/sec/odroidt/system.prop 파일을 아래와 같이 수정 합니다.

1 #
2 # system.prop for odroidt
3 #
4
5 rild.libpath=/system/lib/libreference-ril.so
6 #codewalker
7 #rild.libargs=-d /dev/ttyS0
8 rild.libargs=-d /dev/ttyUSB3
9 ro.sf.lcd_density=240

다음에 linux atdt sk라고 검색하면 HSDPA를 PPP에서 동작 하도록 하는 내용이 있습니다.
이 부분은 x86에서 가져온 chat이 있다면 desktop과 동일하게 처리 되는 부분입니다.

아래 사이트에 가면 ppp에 관한 내용이 있고 HSDAP USB modem에 AT command로 connection하는 내용이 있습니다.


usb_modeswitch를 통해 usb modem을 storage card에서 modem으로 변경 해줍니다.
insmod /modules/usbserial.ko 'vendor=0x1d74 product=0x00c9'으로 ttyUSB 노드를 생성해 줍니다.
여기서 따옴표를 주지 않으면 두번째 parameter product인자가 제대로 넘어가지 않습니다.
ppp call gprs를 호출 하면 t-login 모뎀이 녹색으로 바뀌면서 동작합니다.

지금은 간략하게 작성하였고 차후에 추가 보강하겠습니다.