首页 > 代码库 > mini6410-JNI-led

mini6410-JNI-led

一、编写JNI模块

当安装好NDK编译环境后,会在它的目录下找到sample目录,它里面有一些例子,可以参考这些例子来写我们自已的模块。

 

1在/home/android/文件夹下,新建“ledjni”文件夹。

2/ledjni/jni/目录下,新建“led-jni.c”

led-jni.c文件

 

[html] view plaincopyprint?
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <jni.h>  
  4. #include <fcntl.h> /*包括文件操作,如open() read() close()write()等*/  
  5. #include <android/log.h>  
  6. #define LOG_TAG "led-jni"  
  7.   
  8. #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)  
  9. #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)  
  10.   
  11. #define DEVICE_NAME "/dev/led_by_wenhui" //device point  
  12. //#define DEVICE_NAME "/dev/leds" //device point  
  13. //#define DEVICE_NAME "/dev/led_" //device point  
  14. #define LED_ON  1  
  15. #define LED_OFF 0  
  16.   
  17. int fd;  
  18.   
  19. jstring Java_com_auly_control_ledClass_stringFromJNI( JNIEnv* env, jobject thiz )  
  20. {  
  21.         return (*env)->NewStringUTF(env, "This is wenhui project ,Hello from JNI !");  
  22. }  
  23.   
  24. jint Java_com_auly_control_ledClass_Init( JNIEnv* env)  
  25. {  
  26.         LOGE("LEDclass_Init()\n");  
  27.         fd = open(DEVICE_NAME, 0);  
  28.         LOGE("LEDclass_Init()-> fd = %d \n", fd);  
  29.         if (fd < 0){  
  30.             LOGE("open device %s error \n", DEVICE_NAME);  
  31.             return 0;  
  32.         }  
  33.           
  34.         return 1;  
  35. }  
  36.   
  37. jint Java_com_auly_control_ledClass_IOCTL( JNIEnv* env, jobject thiz , jint ledID, jint ledState)  
  38. {  
  39.       LOGE("IOCTL()-> %d ledState \n",ledState);  
  40.       LOGE("IOCTL()-> %d ledState \n",0);  
  41.       ioctl(fd,ledState, NULL);  
  42.             return 1;  
  43. }  
  44.   
  45. jint Java_com_auly_control_ledClass_CLOSE( JNIEnv* env, jobject thiz )  
  46. {  
  47.         close(fd);  
  48.         return 1;  
  49. }  
#include <stdio.h>
#include <string.h>
#include <jni.h>
#include <fcntl.h> /*包括文件操作,如open() read() close()write()等*/
#include <android/log.h>
#define LOG_TAG "led-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/led_by_wenhui" //device point
//#define DEVICE_NAME "/dev/leds" //device point
//#define DEVICE_NAME "/dev/led_" //device point
#define LED_ON  1
#define LED_OFF 0

int fd;

jstring Java_com_auly_control_ledClass_stringFromJNI( JNIEnv* env, jobject thiz )
{
	    return (*env)->NewStringUTF(env, "This is wenhui project ,Hello from JNI !");
}

jint Java_com_auly_control_ledClass_Init( JNIEnv* env)
{
		LOGE("LEDclass_Init()\n");
		fd = open(DEVICE_NAME, 0);
		LOGE("LEDclass_Init()-> fd = %d \n", fd);
		if (fd < 0){
			LOGE("open device %s error \n", DEVICE_NAME);
			return 0;
		}
		
		return 1;
}

jint Java_com_auly_control_ledClass_IOCTL( JNIEnv* env, jobject thiz , jint ledID, jint ledState)
{
	  LOGE("IOCTL()-> %d ledState \n",ledState);
	  LOGE("IOCTL()-> %d ledState \n",0);
	  ioctl(fd,ledState, NULL);
		    return 1;
}

jint Java_com_auly_control_ledClass_CLOSE( JNIEnv* env, jobject thiz )
{
		close(fd);
	    return 1;
}

 

3、相同目录下的新建Android.mk如下

Android.mk文件

[html] view plaincopyprint?
  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4.   
  5. LOCAL_MODULE    :led-jni  
  6. LOCAL_SRC_FILES :led-jni.c  
  7. LOCAL_CFLAGS := -Werror  
  8. LOCAL_LDLIBS := -llog -lGLESv2  
  9.   
  10. include $(BUILD_SHARED_LIBRARY)  
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := led-jni
LOCAL_SRC_FILES := led-jni.c
LOCAL_CFLAGS := -Werror
LOCAL_LDLIBS := -llog -lGLESv2

include $(BUILD_SHARED_LIBRARY)



可以看到,主要是修改LOCAL_SRC_FILES指向源文件的名称!

还有一点很重要,如果要使用调试LOG打印,也就是__android_log_print函数。要在LOCAL_LDLIBS中添加-llog,如上面的Android.mk所示。

4、编译JNI模块

#cd /home/android/ledjni

进到刚才写的JNI目录

#ndk-build

编译JNI,编译成功后,会在ledjni文件夹下生成libsobj两个文件夹,并在

ledjni/libs/armeabi下得到目标文件libled-jni.so

 

(目前ledjni文件夹只有3个目录jni,libs,obj

 

二、JAVA程序

1Eclipse新建工程 LEDAPP

      注意   Location: 选刚才的 ledjni

 

 

然后 Runas > Android application,就会出现android的模拟器了,里面跑个helloworld出来。

 

2、加入button和文本输出

程序到上面为止代码是ADT自动生成的,似乎与我们一点关系也没有。那我们来改一下代码,因为我们调用JNI接口是为了访问驱动程序操作硬件的,例如写,读,打开LED,关闭LED等等,由按钮触发的动作。

第一步是,增加两个Button,,在main.xml里描述一下:打开Res> layout> main.xml 文件

[html] view plaincopyprint?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:orientation="vertical"  
  4.     android:layout_width="fill_parent"  
  5.     android:layout_height="fill_parent"  
  6.     >  
  7. <TextView    
  8.     android:layout_width="fill_parent"   
  9.     android:layout_height="wrap_content"   
  10.     android:text="@string/hello"  
  11.     />  
  12.       
  13. <Button android:id="@+id/led_on"  
  14.     android:layout_width="wrap_content"  
  15.     android:layout_height="wrap_content"  
  16.     android:text="@string/LEDon"  
  17.     />  
  18.       
  19.       
  20. <Button android:id="@+id/led_off"  
  21.     android:layout_width="wrap_content"  
  22.     android:layout_height="wrap_content"  
  23.     android:text="@string/LEDoff"  
  24.     />  
  25.       
  26. </LinearLayout>  
<?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"
	android:layout_width="wrap_content"
 	android:layout_height="wrap_content"
 	android:text="@string/LEDon"
 	/>
    
    
<Button android:id="@+id/led_off"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="@string/LEDoff"
	/>
	
</LinearLayout>

实际代码中,把注释去掉,否则编译不过的。

3、加入输出字符串资源

工程 >values > strings.xml文件

 

修改如下

<?xmlversion=
"1.0"encoding="utf-8"?>
<resources>
<stringname=
"hello">Led
控制程序</string>
<stringname=
"app_name">LEDAPP</string>
<stringname=
"LEDon">
打开LED</string>
<stringname=
"LEDoff">
关闭LED</string>
</resources>

上面的”打开LED”等资源,就是用在按钮上显示出来的字符串

经过上面的修改,现在程序界面上,已经有如下效果了

鼠标右键工程名>Runas > Android application运行程序。

 

4、加入按钮对应的动作

关闭LED”按钮:

打开LED”按扭:调用JNIIOCTL(int ledID, int ledState);

操作:

LEDAPP> src > com.auly.control >LEDAPPActivity.java文件

 

 

[html] view plaincopyprint?
  1. package com.auly.control;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.view.View;  
  6. import android.view.View.OnClickListener;  
  7. import android.widget.Button;  
  8.   
  9. public class LEDAPPActivity extends Activity {  
  10.     /** Called when the activity is first created. */  
  11.     //定义变量  
  12.     public static final int LED_ON = 0X01;  
  13.     public static final int LED_OFF = 0x00;  
  14.     private  Button btn1 = null;  
  15.     private  Button btn2 = null;  
  16.       
  17.     //定义类  
  18.     ledClass myledclass;  
  19.   
  20.     @Override  
  21.     protected void onCreate(Bundle savedInstanceState) {  
  22.         // TODO Auto-generated method stub  
  23.         super.onCreate(savedInstanceState);  
  24.           
  25.         //初始化   
  26.         setContentView(R.layout.main);   
  27.         myledclass = new ledClass();   //声明类  
  28.         myledclass.Init();             //调用JNI库里的初始化函数   
  29.           
  30.         //按钮 打开 led  
  31.         btn1 = (Button)findViewById(R.id.led_on);  
  32.         btn1.setOnClickListener(new MyBtn1Listener());  //捆绑监听器  
  33.           
  34.         //按钮 关闭 led   
  35.         btn2 = (Button)findViewById(R.id.led_off);  
  36.         btn2.setOnClickListener(new MyBtn2Listener());  //捆绑监听器        
  37.     }  
  38.       
  39.     class MyBtn1Listener implements OnClickListener {  
  40.         @Override  
  41.         public void onClick(View v) {  
  42.             myledclass.Init();  
  43.             System.out.println("debug LED_ON");  
  44.             myledclass.IOCTL(0,LED_ON);  
  45.         }  
  46.     }  
  47.       
  48.     class MyBtn2Listener implements OnClickListener {  
  49.         @Override  
  50.         public void onClick(View v) {  
  51.             System.out.println("debug LED_OFF");  
  52.             myledclass.IOCTL(0,LED_OFF);  
  53.             myledclass.CLOSE();  
  54.         }  
  55.     }  
  56. }  
package com.auly.control;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class LEDAPPActivity extends Activity {
    /** Called when the activity is first created. */
	//定义变量
	public static final int LED_ON = 0X01;
	public static final int LED_OFF = 0x00;
    private  Button btn1 = null;
    private  Button btn2 = null;
	
    //定义类
	ledClass myledclass;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		
		//初始化 
		setContentView(R.layout.main); 
		myledclass = new ledClass();   //声明类
        myledclass.Init();             //调用JNI库里的初始化函数 
        
        //按钮 打开 led
        btn1 = (Button)findViewById(R.id.led_on);
        btn1.setOnClickListener(new MyBtn1Listener());  //捆绑监听器
        
        //按钮 关闭 led 
        btn2 = (Button)findViewById(R.id.led_off);
        btn2.setOnClickListener(new MyBtn2Listener());  //捆绑监听器      
	}
	
	class MyBtn1Listener implements OnClickListener {
    	@Override
    	public void onClick(View v) {
    		myledclass.Init();
    		System.out.println("debug LED_ON");
			myledclass.IOCTL(0,LED_ON);
    	}
    }
	
	class MyBtn2Listener implements OnClickListener {
    	@Override
    	public void onClick(View v) {
    		System.out.println("debug LED_OFF");
			myledclass.IOCTL(0,LED_OFF);
			myledclass.CLOSE();
    	}
    }
}

 

5、添加类ledClass

鼠标右键com.auly.control> new > Class

 

填参数:

 

Finish后,在/src/com/auly/control/得到如下的类文件

ledClass.java

修改如下

package com.auly.control;

public class ledClass {
    /*声明函数*/
    //初始化函数 对应 JNI 里面的 jint Java_com_auly_control_ledClass_Init( JNIEnv* env) 函数 以下的同理
    public native int Init();
    public native int IOCTL(int ledID, int ledState);
    public native String stringFromJNI();
    public native int CLOSE();
    static{
        System.loadLibrary("led-jni");/*加载JNI库*/
    }
}

三、 编译运行

鼠标右键工程名,弹出菜单,选择 Runas > Android Application就可以看到编译过程,编译完成后,会自动调用android模拟器,看到界面效果

 

安装到开发板:(方式有多种 adb ) 或直接用u盘拷贝(这样调试比较麻烦)

LEDSJNI目录下,会看到bin文件夹,里面的LEDAPP.apk就是这个程序的安装文件,可以把它安装的开发板上,运行本程序,看控制开发板上的LED灯的效果。

注意!运行前 要修改的驱动节点的权限

#chmod777 /dev/vib

     这是为了使得led_by_wenhui这个节点可以被我们写的JNI操作,不然会open失败的,因为APK安装的JNI模块,权限不够,这个节点是我们的LED驱动生成的控制节点。

也可以在android文件系统yaffs编译时,通过init.rc文件来实现这个操作,就是在该文件里随便一行,写上面的命令行,启动时会自动执行!这样就不用手动的改变该节点的属性了。

拷贝LEDAPP.apk到开发板上,通过安装工具把它安装到开发板上

运行程序,就能按程序上的近钮来控制开发板上的LED亮灭了!