本文前提:我們假設已經寫了一個驅動程序,它是控制LED的亮滅的,並且創建了一個節點:/dev/vib,也就是通過open這個vib節點,可以read/write/ioctl 操作驅動程序實現LED燈的亮滅控制,具體可以看我另一篇博文《android驅動例子(LED燈控制)》
開發環境 1、ubuntu下的NDK編譯環境,2、Esclips開發環境
一、編寫JNI模塊
當安裝好NDK編譯環境後,會在它的目錄下找到sample目錄,它裏面有一些例子,可以參考這些例子來寫我們自已的模塊。
1、 source文件夾下,新建“LEDSJNI”文件夾。
2、 Source/LEDSJNI/jni/目錄下,新建“vib-jni.c”
vib-jni.c文件
#include
#include
#include /*包括文件操作,如open() read() close() write()等*/
//----for output the debug log message
#include
#define LOG_TAG "vib-jni"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#define DEVICE_NAME "/dev/vib" //device point
#define VIB_ON 0x11
#define VIB_OFF 0x22
int fd;
jstring
Java_com_auly_control_vibClass_stringFromJNI( JNIEnv* env,
jobject thiz )
{
return (*env)->NewStringUTF(env, "Hello from JNI--Peter for vib!");//打印字符串
}
jint
Java_com_auly_control_vibClass_Init( JNIEnv* env )
{
LOGE("vibClass_Init() /n");
fd = open(DEVICE_NAME,O_RDWR);//打開設備
LOGE("vibClass_Init()-> fd = %d /n",fd);
if(fd == -1)
{
LOGE("open device %s error /n ",DEVICE_NAME);//打印調試信息
return 0;
}
else
{
return 1;
}
}
jint
Java_com_auly_control_vibClass_IOCTLVIB( JNIEnv* env, jobject thiz, jint controlcode )
{
int CTLCODE = controlcode;
LOGE("IOCTLVIB() = %x --vibClass_IOCTLVIB /n",CTLCODE);
switch(CTLCODE)
{
case VIB_ON:
{
ioctl(fd,VIB_ON);//調用驅動程序中的ioctrl接口,把命令VIB_ON傳下去,實現硬件操作
break;
}
case VIB_OFF:
{
ioctl(fd,VIB_OFF);//調用驅動程序中的ioctrl接口,把命令VIB_OFF傳下去,實現硬件操作
break;
}
default:break;
}
return 1;
}
3、相同目錄下的新建Android.mk如下
Android.mk文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := vib-jni
LOCAL_SRC_FILES := vib-jni.c
LOCAL_CFLAGS := -Werror
LOCAL_LDLIBS := -llog -lGLESv2 //__android_log_print 函數
include $(BUILD_SHARED_LIBRARY)
可以看到,主要是修改LOCAL_SRC_FILES指向源文件的名稱!
還有一點很重要,如果要使用調試LOG 打印,也就是__android_log_print 函數。要在LOCAL_LDLIBS中添加-llog,如上面的Android.mk所示。
4、編譯JNI模塊
#cd /home/workspace/android-ndk-r4b/sources/LEDSJNI
進到剛纔寫的JNI目錄
#ndk-build
編譯JNI,編譯成功後,會在LEDSJNI文件夾下生成libs和obj兩個文件夾,並在
LEDSJNI/libs/armeabi下得到目標文件libvib-jni.so
(目前LEDSJNI文件夾只有3個目錄jni,libs,obj)
二、JAVA程序
1、Eclipse新建工程
拷貝LEDSJNI目錄到Windows下,例如C盤下。然後在它裏面新建Eclipse 工程。
新鍵工程後,
如果出現如下錯誤:
ERROR: Unable to open class file C:/LEDSJNI/gen/com/auly/control/R.java: No such file or directory
解決方法如下:
對着該工程鼠標右鍵 》bulid path 》configure build path》java build path》order and Export
把裏面的android 2.1勾上,Build project,就OK了
然後 Run as > Android application,就會出現android的模擬器了,裏面跑個helloworld出來。
2、加入button和文本輸出
程序到上面爲止代碼是ADT自動生成的,似乎與我們一點關係也沒有。那我們來改一下代碼,因爲我們調用JNI接口是爲了訪問驅動程序操作硬件的,例如寫,讀,打開LED,關閉LED等等,由按鈕觸發的動作。
第一步是,增加兩個Button,,在main.xml裏描述一下:打開Res > layout> main.xml 文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button android:id="@+id/led_on"/*這表示需要一個唯一的UID來作爲Button的ID,它的引用名是led_on。*/
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/LEDon">/*表示這個按鈕的文本是來源於另一個資源描述文件strings.xml裏的文:字資源LEDon */
<requestFocus/>
</Button>
<Button android:id="@+id/led_off"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/LEDoff">
<requestFocus/>
</Button>
</LinearLayout>
實際代碼中,把註釋去掉,否則編譯不過的。
3、加入輸出字符串資源
工程 > values > strings.xml 文件
修改如下 "1.0" encoding="utf-8"?> "hello">Led 控制程序 "app_name">LEDAPP "LEDon">打開LED "LEDoff">關閉LED
上面的”打開LED”等資源,就是用在按鈕上顯示出來的字符串
經過上面的修改,現在程序界面上,已經有如下效果了
鼠標右鍵工程名>Run as > Android application 運行程序。
4、加入按鈕對應的動作
“打開LED”按扭:調用JNI的IOCTLVIB(VIB_ON);
“關閉LED”按鈕:調用JNI的 IOCTLVIB(VIB_OFF);
操作:
在LEDAPP > src > com.auly.control > vibrator.java文件
package com.auly.control;
/**定義頭文件*/
import android.widget.TextView;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.util.Log;
import android.app.Activity;
import android.os.Bundle;
public class vibrator extends Activity {
/** 定義變量 */
public static final int VIB_ON = 0x11;
public static final int VIB_OFF = 0x22;
vibClass mvibClass;/**定義類*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/**----------------初始化------------- */
mvibClass = new vibClass();/*聲明類*/
mvibClass.Init(); //調用JNI庫裏的初始化函數
/**----------------按鈕:打開LED------------- */
Button btn1 = (Button)findViewById(R.id.led_on);/*這裏用到的ID,就是在main.xml裏定義的 led_on*/
btn1.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v) /**當按鈕按下*/
{
mvibClass.IOCTLVIB(VIB_ON);
}
});
/**----------------按鈕:關閉LED------------- */
Button btn2 = (Button)findViewById(R.id.led_off);/*聲明按鈕,id main.xml裏有定義*/
btn2.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v) /**當按鈕按下*/
{
mvibClass.IOCTLVIB(VIB_OFF);
}
});
}
}
如果在保存時遇到說 save problems,無法保存,請先複製上面的代碼,然後,關閉vibrator.java,提示保存時選不保存,然後在左邊資源窗中再次雙擊打開該文件,把幾日才複製下來的內容,粘貼上去,一般就能正常保存,不知道是不是Eclipse的不穩定造成的。
5、添加類vibClass
鼠標右鍵com.auly.control > new > Class
填參數:
Finish後,在/src/com/auly/control/得到如下的類文件
vibClass.java
修改如下
package com.auly.control;
/*Class for Vibrator --peter*/
public class vibClass {
static {
System.loadLibrary("vib-jni");/*加載JNI庫*/
}
/*聲明 函數*/
public static native String stringFromJNI();/*輸出字符串
對應於JNI裏面的
jstring Java_com_auly_control_vibClass_stringFromJNI( JNIEnv* env,jobject thiz )
*/
public static native int Init();/*初始化函數,對應於JNI裏面的
jint Java_com_auly_control_vibClass_Init( JNIEnv* env )
*/
public static native int IOCTLVIB(int controlcode);
/*IO CTRL 接口
* 對應於JNI裏的
jint Java_com_auly_control_vibClass_IOCTLVIB( JNIEnv* env, jobject thiz, jint controlcode )
*/
}
三、 編譯運行
鼠標右鍵工程名,彈出菜單,選擇 Run as > Android Application 就可以看到編譯過程,編譯完成後,會自動調用android模擬器,看到如下效果
安裝到開發板:
在C:/LEDSJNI目錄下,會看到bin文件夾,裏面的LEDAPP.apk就是這個程序的安裝文件,可以把它安裝的開發板上,運行本程序,看控制開發板上的LED燈的效果。
步驟:
1、開發板上跑的kenel就已經把了LED驅動編譯在裏面了,
可以參考《android驅動例子(LED燈控制)》
2、開發板android跑起來後,PC機打開串口工具例如DNW,打開與開發板連接的COM口,然後敲打回車,就會在終端裏看到“#”並有光標,表面進入了開發板的命令行終端,
輸入命令:
#chmod 777 /dev/vib
這是爲了使得vib這個節點可以被我們寫的JNI操作,不然會open失敗的,因爲APK安裝的JNI模塊,權限不夠,這個節點是我們的LED驅動生成的控制節點。
也可以在android文件系統yaffs編譯時,通過init.rc 文件來實現這個操作,就是在該文件裏隨便一行,寫上面的命令行,啓動時會自動執行!這樣就不用手動的改變該節點的屬性了。
3、拷貝LEDAPP.apk到開發板上,通過安裝工具把它安裝到開發板上,如果不會安,可以GOOGLE一下,
4、運行程序,就能按程序上的近鈕來控制開發板上的LED亮滅了!