JNI綜合實驗二:IO控制及驅動打開與關閉

第一步:首先在linux下添加驅動

1.查看原理圖,找出未使用的引腳,這裏是:GPJ0_0 GPJ0_1

2.添加char字符設備驅動,找到LINUX源代碼下的char設備驅動路徑: FriendlyArm /Linux3.0.8/ Drivers/char/目錄,在目錄下新建裏一個文件lzm_fjicc.c 用來寫驅動用。

需要註冊設備、設備的打開、關閉、取消設備等操作。

源代碼如綜合實驗一:

 

第二步:建立Android測試代碼,第一步要實現.so文件:

1.打開eclipseàFileàNewàAndroid Application Projectcom.example.TEST

2.新建jni文件夾,在文件夾內新建兩個文件:test-jni.cAndroid.mk

Android.mk內容如下:

# Copyright (C) 2009 The Android Open Source Project

#

# Licensed under the Apache License, Version 2.0 (the "License");

# you may not use this file except in compliance with the License.

# You may obtain a copy of the License at

#

#http://www.apache.org/licenses/LICENSE-2.0

#

# Unless required by applicable law or agreed to in writing, software

# distributed under the License is distributed on an "AS IS" BASIS,

# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

# See the License for the specific language governing permissions and

# limitations under the License.

#

LOCAL_PATH := $(call my-dir)

 

include$(CLEAR_VARS)

 

LOCAL_MODULE:= test-jni

LOCAL_SRC_FILES := test-jni.c

 

include$(BUILD_SHARED_LIBRARY)

jni0922.c內容如下:

/*

* Copyright (C) 2009 The Android Open Source Project

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

*http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*

*/

#include<termios.h>

#include<unistd.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<sys/ioctl.h>

#include<fcntl.h>

#include<string.h>

#include<jni.h>

#include<errno.h>

//#include <utils/Log.h>

//#include <system.h>

 

#define VIB_ON 0x11

#define VIB_OFF 0x22

 

 

 

#defineDEV_NAME "/dev/LZM_FJICC"

/* This is a trivial JNI example where we use a native method

* to return a new VM String. See the corresponding Java source

* file located at:

*

*/project/app/TEST/src/com.example.TEST/MainActivity.java

*/project/app/TEST/src/com.example.TEST/TESTCLASS.java

*/

jstring

Java_com_example_TEST_TESTCLASS_stringFromJNI( JNIEnv* env, jobject thiz )

{

return (*env)->NewStringUTF(env, "Hello from JNI !");

}

 

jint

Java_com_example_TEST_TESTCLASS_IOCTL( JNIEnv* env, jobject thiz, jint fd ,jint controlcode,jint ledid)

{

/* LED */

int CTLCODE = controlcode;

int value =-1;

switch(CTLCODE)

{case VIB_ON:

{

ioctl(fd,1,ledid);//setLedState( 0, 1 );//調用驅動程序中的ioctrl接口,把命令傳下去,實現硬件操作

break;

}

case VIB_OFF:

{

ioctl(fd,0,ledid);////setLedState( 0, 0 );//調用驅動程序中的ioctrl接口,把命令傳下去,實現硬件操作

break;

}

 

default:break;

}

return fd;

}

 

jint

Java_com_example_TEST_TESTCLASS_OPEN(JNIEnv* env,jobject thiz)

{

 

jint fd;

fd=open(DEV_NAME,O_RDWR);

return fd;

}

 

jint

Java_com_example_TEST_TESTCLASS_CLOSE( JNIEnv* env, jobject thiz, jint fd)

{

jint ret;

ret = close(fd);

return ret;

}

 

 

注意如果需要頭文件Alog.h需要自己寫,然後放在jni文件夾下的

#pragma once

#include<android/log.h>

#define LOG_TAG "debug log"

#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##args)

#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)

#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args)

 

 

 

3.建立完畢,打開Cygwin工具,並進入到工程目錄下的jni目錄下:

$ cd d:/Program/Android/workspace/TEST /jni

$$NDK/ndk-build

 

這樣就OK了,生成了libtest-jni.so文件了,自動生成到了工程目錄下的libs/armeabi/ libtest-jni.so,發現test-jni是我們剛纔在.mk文件裏面的命名。

 

第三步:寫應用程序:

1.在應用程序類com.example.TEST目錄下建立一個類:TESTCLASS.java,輸入如下代碼,這是用來引用libtest-jni.so文件的。

package com.example.TEST;

 

import android.util.Log;

 

publicclass TESTCLASS {

 

publicnative String stringFromJNI();

publicnativeint OPEN();

publicnativeint IOCTL(int fd,int controlcode,int ledID);

publicnativeint CLOSE(int fd);

 

static {

try {

System.loadLibrary("test-jni");

} catch (UnsatisfiedLinkError e) {

Log.d("HardwareControler", "HardwareControler ibrary not found!");

}

}

}

 

2.編寫應用程序,調用TESTCLASS類中的函數OPEN()/CLOSE()/IOCTL()就可以實現底層的控制了。

添加按鈕,用來打開和關閉LED,以及關閉驅動

<Button

android:id="@+id/button1"

style="?android:attr/buttonStyleSmall"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:layout_weight="0.76"

android:text="ON" />

 

<Button

android:id="@+id/button2"

style="?android:attr/buttonStyleSmall"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_weight="1.26"

android:text="OFF" />

 

<Button

android:id="@+id/button5"

style="?android:attr/buttonStyleSmall"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_weight="0.76"

android:text="close" />

2.編寫MainActivity,添加響應函數:

package com.example.TEST;

 

import java.io.DataOutputStream;

import java.io.IOException;

 

import android.os.Bundle;

import android.app.Activity;

import android.view.Menu;

import android.view.View;

import android.widget.Button;

import android.widget.Toast;

 

publicclass MainActivity extends Activity {

 

private Button btn_on;

private Button btn_off,btn_close;

 

publicstaticfinalintVIB_ON = 0x11;

publicstaticfinalintVIB_OFF = 0x22;

intfd;

intvalue = -1;

TESTCLASS mTESTCLASS1;

 

@Override

protectedvoid onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

 

setContentView(R.layout.activity_main);

mTESTCLASS1 = new TESTCLASS();

String s = mTESTCLASS1.stringFromJNI().toString();

 

//修改驅動的權限LZM_FJICC

changePerm();

 

 

fd = mTESTCLASS1.OPEN();

Toast.makeText(MainActivity.this, "open,fd="+fd, Toast.LENGTH_SHORT).show();

 

btn_on = (Button)findViewById(R.id.button1);

btn_off = (Button)findViewById(R.id.button2);

btn_close= (Button)findViewById(R.id.button5);

 

 

 

 

if(fd == -1)

Toast.makeText(MainActivity.this, "沒有打開設備", Toast.LENGTH_SHORT).show();

else

Toast.makeText(MainActivity.this, "打開設備", Toast.LENGTH_SHORT).show();

 

Toast.makeText(MainActivity.this,""+s, Toast.LENGTH_SHORT).show();

 

btn_on.setOnClickListener(new Button.OnClickListener(){

 

@Override

publicvoid onClick(View arg0) {

// TODO Auto-generated method stub

fd=mTESTCLASS1.IOCTL(fd, VIB_ON,0);

Toast.makeText(MainActivity.this, "ioctl,fd="+fd, Toast.LENGTH_SHORT).show();

}

});

 

 

btn_off.setOnClickListener(new Button.OnClickListener(){

 

@Override

publicvoid onClick(View v) {

// TODO Auto-generated method stub

mTESTCLASS1.IOCTL(fd, VIB_OFF,0);

 

}});

 

 

 

btn_close.setOnClickListener(new Button.OnClickListener(){

 

@Override

publicvoid onClick(View v) {

// TODO Auto-generated method stub

Toast.makeText(MainActivity.this, "close,fd="+fd, Toast.LENGTH_SHORT).show();

if(fd != -1){

value = mTESTCLASS1.CLOSE(fd);

if(value == -1)

Toast.makeText(MainActivity.this, "close fail,fd="+value, Toast.LENGTH_SHORT).show();

else

Toast.makeText(MainActivity.this, "close success,fd="+value, Toast.LENGTH_SHORT).show();

}else{

Toast.makeText(MainActivity.this, "設備未打開,無需關閉", Toast.LENGTH_SHORT).show();

}

}

 

});

 

 

}

 

void changePerm()

{

Process chperm;

try {

chperm=Runtime.getRuntime().exec("su");

 

 

DataOutputStream os =

new DataOutputStream(chperm.getOutputStream());

os.writeBytes("chmod 777 /dev/LED_LZM_FJICC\n");

os.flush();

 

os.writeBytes("exit\n");

os.flush();

 

chperm.waitFor();

 

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

問題一:android NDK jni下的c文件 Unresolved inclusion

原因是在eclipse編輯環境中沒有找到對應的include中的文件。解決方法是將包含該文件的include目錄作爲新的linked folder加入工程中。具體方法如下:
1.
右擊工程->New->Folder

2. 對話框中點擊Advanced

3. 選擇Link to alternate location (Linked Folder),選擇需要的include目錄

4. Finish後刷新工程,問題解決。

include 目錄可以在ndk的安裝目錄中找到

比如:在安裝的NDK目錄下找到/NDKDir/android-ndk-r7b/platforms/android-8/arch-arm/usr/include

 

問題二:在android裏使用JNI,總是報錯:insomethingnotastructureorunion

error:requestformember'GetStringUTFChars'insomethingnotastructureorunion

問題解決了,原來是這樣的:
如果是c程序,要用(*env)->
如果是C++要用env->

linux下如果.c文件中用“env->”編譯會找不到此結構,必須用“(*env)->”,或者改成.cpp文件,以c++的方式來編譯

以下是兩者的區別:
jni.h

structJNINativeInterface_;
structJNIEnv_;
#ifdef__cplusplus
typedefJNIEnv_JNIEnv;
#else
typedefconststructJNINativeInterface_*JNIEnv;
#endif

/*
*WeuseinlinedfunctionsforC++sothatprogrammerscanwrite:
*env->FindClass("java/lang/String")
*inC++ratherthan:
*(*env)->FindClass(env,"java/lang/String")
*inC.
*/
C++中使用
env->FindClass("java/lang/String")
C
中使用
(*env)->FindClass(env,"java/lang/String")

 

 

問題三:直接在應用程序中獲取驅動的可執行權限#chmod 777

//用來修改驅動的權限問題否則需要在終端輸入 #chmod 777 /dev/LZM_FJICC

void changePerm()

{

Process chperm;

try {

chperm=Runtime.getRuntime().exec("su");

DataOutputStream os =

new DataOutputStream(chperm.getOutputStream());

os.writeBytes("chmod 777 /dev/LZM_FJICC\n");

os.flush();

os.writeBytes("exit\n");

os.flush();

chperm.waitFor();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

 

問題四:S5VP210端口設置小結

//定義用到的引腳S5PV210_GPJ0(7)

//設置引腳的輸出

s3c_gpio_cfgpin(S5PV210_GPJ0(7),S3C_GPIO_SFN(1));//設置爲輸出

gpio_direction_output(S5PV210_GPJ0(7),0);

 

//釋放總線

#define OW_Pin S5PV210_GPJ0(7)

s3c_gpio_cfgpin(OW_Pin,S3C_GPIO_SFN(0));//設置爲輸入

s3c_gpio_setpull(OW_Pin,S3C_GPIO_PULL_UP);

gpio_get_value(OW_Pin)//獲取引腳的輸入電平狀態

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章