`

JNI综合实验一:LED点亮+IO电平读取

 
阅读更多

第一步:首先在linux下添加驱动

第二步:建立Android测试代码---实现.so文件

第三步:写应用程序

 

问题一:android NDK jni下的c文件 Unresolved inclusion

问题二:在android里使用JNI,总是报错:insomethingnotastructureorunion

问题三:直接在应用程序中获取驱动的可执行权限#chmod 777

问题四:S5VP210端口设置小结

 

第一步:首先在linux下添加驱动

1.查看原理图,找出未使用的引脚,这里是:GPJ0_0 GPJ0_1

2.添加char字符设备驱动,找到LINUX源代码下的char设备驱动路径: FriendlyArm /Linux3.0.8/ Drivers/char/目录,在目录下新建里一个文件lzm_fjicc.c 用来写驱动用。

需要注册设备、设备的打开、关闭、取消设备等操作。

源代码如下:

//lzm_fjicc.c

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <linux/init.h>

#include <linux/delay.h>

#include <linux/sched.h>

#include <linux/poll.h>

#include <linux/irq.h>

#include <asm/irq.h>

#include <asm/io.h>

#include <linux/interrupt.h>

#include <asm/uaccess.h>

#include <mach/hardware.h>

#include <linux/platform_device.h>

#include <linux/cdev.h>

#include <linux/miscdevice.h>

 

#include <mach/map.h>

#include <mach/gpio.h>

#include <mach/regs-clock.h>

#include <mach/regs-gpio.h>

 

#define DEVICE_NAME "LZM_FJICC"

 

static int lzm_gpios[] = {

S5PV210_GPJ0(0),

S5PV210_GPJ0(1),

S5PV210_GPJ0(2),//设置为输入,读取次引脚的状态

};

#define GPIO_NUMARRAY_SIZE(lzm_gpios)

 

static int lzm_open(struct inode *inode, struct file *file)

{

int ret;

int i;

for (i = 0; i < GPIO_NUM; i++) {

ret = gpio_request(lzm_gpios[i], "GPIO");

if (ret) {

printk("%s: request GPIO %d failed, ret = %d\n", DEVICE_NAME,

lzm_gpios[i], ret);

return ret;

}

s3c_gpio_cfgpin(lzm_gpios[i], S3C_GPIO_OUTPUT); //设置为输出状态

gpio_set_value(lzm_gpios[i], 1);//默认高电平

}

 

//set to be input and pullup

s3c_gpio_cfgpin(lzm_gpios[2], S3C_GPIO_INPUT); //设置为输入状态

s3c_gpio_setpull(lzm_gpios[2],S3C_GPIO_PULL_UP);//上拉

 

//ret = misc_register(&lzm_dev);//register devices to core

printk(DEVICE_NAME"\t open success!\n");

 

return 0;

}

 

static int lzm_close(struct inode *inode, struct file *file)

{

 

int i;

for (i = 0; i < GPIO_NUM; i++) {

gpio_free(lzm_gpios[i]);

}

//misc_deregister(&lzm_dev);

printk(DEVICE_NAME"\t close success! \n");

return 0;

}

 

static long lzm_ioctl(struct file *filp, unsigned int cmd,

unsigned long arg)

{

int temp;

switch(cmd) {

 

case 0://write0

if (arg > GPIO_NUM) {

return -EINVAL;

}

gpio_set_value(lzm_gpios[arg],0);

//printk(DEVICE_NAME": %d %d\n", arg, cmd);

break;

case 1://write1

if (arg > GPIO_NUM) {

return -EINVAL;

}

gpio_set_value(lzm_gpios[arg],1);

//printk(DEVICE_NAME": %d %d\n", arg, cmd);

break;

case 3://read GPJ0_2 state//读取端口状态

temp = gpio_get_value(S5PV210_GPJ0(2));

udelay(50);//delay for

printk("read the GPJ0_2 value :%d\n",temp);

return temp;

break;

default:

return -EINVAL;

}

 

return 0;

}

 

static struct file_operations dev_fops = {

.owner= THIS_MODULE,

.open= lzm_open,

.unlocked_ioctl= lzm_ioctl,

.release= lzm_close,

};

 

static struct miscdevice lzm_dev = {

.minor= MISC_DYNAMIC_MINOR,

.name= DEVICE_NAME,

.fops= &dev_fops,

};

 

 

//register device

static int __init dev_init(void)

{

int ret;

ret = misc_register(&lzm_dev);

printk(DEVICE_NAME"\t registered!\n");

return ret;

}

 

//disregister device

static void __exit dev_exit(void)

{

 

misc_deregister(&lzm_dev);

printk("\texit!\n");

}

 

module_init(dev_init);

module_exit(dev_exit);

 

MODULE_LICENSE("GPL");//驱动类型

MODULE_AUTHOR("LZM");//作者信息

MODULE_DESCRIPTION("TEST TEST");//驱动描述

 

第二步:建立Android测试代码,第一步要实现.so文件:

1.打开eclipseàFileàNewàAndroid Application Projectcom.example.lzm0922

 

2.新建jni文件夹,在文件夹内新建两个文件:jni0922.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:= jni0922

LOCAL_SRC_FILES := jni0922.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<ALog.h>

//#include <system.h>

 

#define OFF 0x11

#define ON 0x22

#define READ 0x33

 

 

#defineDEV_NAME "/dev/LZM_FJICC"

int fd;

/* 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.lzm0922/MainActivity.java

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

*/

jstring

Java_com_example_lzm0922_TESTCLASS_stringFromJNI( JNIEnv* env, jobject thiz )

{

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

}

 

jint

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

{

/* LED */

int CTLCODE = controlcode;

int value =-1;

switch(CTLCODE)

{case ON:

{

ioctl(fd,1,ledid);//setLedState( 0, 1 );//调用驱动程序中的ioctrl接口,把命令传下去,实现硬件操作

break;

}

case OFF:

{

ioctl(fd,0,ledid);////setLedState( 0, 0 );//调用驱动程序中的ioctrl接口,把命令传下去,实现硬件操作

break;

}

 

 

case READ:

{

value=ioctl(fd,3,ledid);// 2 表示读取状态的cmd01表示led控制的命令;

return value;

break;

}

default:break;

}

 

return 0;

 

 

}

 

jint

Java_com_example_lzm0922_TESTCLASS_OPEN(JNIEnv* env)

{

fd=open(DEV_NAME,O_RDWR);

return fd;

}

 

int

Java_com_example_lzm0922_TESTCLASS_CLOSE(JNIEnv* env)

{int 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/lzm0922/jni

$$NDK/ndk-build

 

这样就OK了,生成了libjni0922.so文件了,自动生成到了工程目录下的libs/armeabi/ libjni0922.so,发现jni0922是我们刚才在.mk文件里面的命名。

 

第三步:写应用程序:

1.在应用程序类com.example.lzm0922目录下建立一个类:TESTCLASS.java,输入如下代码,这是用来引用libjni0922.so文件的。

package com.example.lzm0922;

 

import java.io.File;

import java.io.FileDescriptor;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

 

import android.util.Log;

 

publicclass TESTCLASS{

 

publicnative String stringFromJNI();

publicnativeint OPEN();

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

publicnativeint CLOSE();

static {

try {

System.loadLibrary("jni0922");

} catch (UnsatisfiedLinkError e) {

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

}

}

}

 

2.编写应用程序,调用TESTCLASS类中的函数OPEN()/CLOSE()/IOCTL()就可以实现底层的控制了。

添加两个按钮,用来打开和关闭LED灯,以及读取端口的状态

<Button

android:id="@+id/myButtonOff"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_alignRight="@+id/button1"

android:layout_below="@+id/button1"

android:layout_marginTop="28dp"

android:text="GPJ0_OFF" />

 

<Button

android:id="@+id/myButtonRd"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_alignLeft="@+id/myButtonOff"

android:layout_centerVertical="true"

android:text="GPJ0_RD" />

 

<Button

android:id="@+id/myButtonOn"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_alignLeft="@+id/myButtonOff"

android:layout_below="@+id/myButtonOff"

android:layout_marginTop="27dp"

android:text="GPJ0_ON" />

 

2.编写MainActivity,添加响应函数:

package com.example.lzm0922;

 

 

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,btn_off;

private Button btn_rd;

 

publicstaticfinalintON = 0x22;

publicstaticfinalintOFF = 0x11;

publicstaticfinalintREAD = 0x33;

intfd;

intvalue = -1;

public String s;

TESTCLASS mTESTCLASS1;

 

@Override

protectedvoid onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

 

setContentView(R.layout.activity_main);

 

mTESTCLASS1 = new TESTCLASS();

 

 

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

 

//修改驱动的权限LED_LZM_FJICC

changePerm();

 

fd=mTESTCLASS1.OPEN();

 

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

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

btn_rd = (Button)findViewById(R.id.myButtonRd);

 

 

if(fd == -1)

Toast.makeText(MainActivity.this, "没有打开设备 "+"fd="+fd, Toast.LENGTH_SHORT).show();

else

Toast.makeText(MainActivity.this, "打开设备"+" fd="+fd, 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

mTESTCLASS1.IOCTL(fd,ON,0);

}

});

 

btn_off.setOnClickListener(new Button.OnClickListener(){

 

@Override

publicvoid onClick(View v) {

// TODO Auto-generated method stub

mTESTCLASS1.IOCTL(fd,OFF,0);

 

}});

btn_rd.setOnClickListener(new Button.OnClickListener(){

 

@Override

publicvoid onClick(View v) {

// TODO Auto-generated method stub

value = mTESTCLASS1.IOCTL(fd,READ,1);

Toast.makeText(MainActivity.this, "GPJ0_2="+value, Toast.LENGTH_SHORT).show();

}});

 

 

}

 

@Override

protectedvoid onDestroy() {

// TODO Auto-generated method stub

super.onDestroy();

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

int temp = mTESTCLASS1.CLOSE();

if(temp == -1)

Toast.makeText(MainActivity.this, "Close Failed fd="+temp, Toast.LENGTH_SHORT).show();

else

Toast.makeText(MainActivity.this, "Close Success fd="+temp, 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/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)//获取引脚的输入电平状态

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics