您的位置:首页 > 移动开发 > Android开发

android jni的编写, 控制led灯

2013-06-17 18:11 302 查看
         jni, java native interface, java的本地接口,如果java代码想去调用native方法(实际就是c/c++函数),就需要用jni技术,在传统的java中jni技术就已经存在,但是由于传统的java代码中,不太去写架构或者平台相关的代码,所以以前jni不是太惹人注意,直到android出现后,android本身是一个linux操作系统, linux中的应用编程中就使用c/c++代码去调用驱动,假如android的应用apk想去调用底层的设备驱动,那么就必须要去调用c/c++代码,所以此时jni就显得很重要,它起着承上启下的作用.

           jni的写法有好几种,在这里先介绍在android源码包+linux环境下的jni编程方式,随后会介绍ndk中的jni的编程方式

           编程之前首先需要给大家介绍一个大体的框架,我们需要在apk中去点一个led灯,此时就像做饭一样,介绍几个主料:

            1, apk,实现button点灯

             2, jni代码,调用linux的系统调用,去控制驱动

             3, 驱动,完成控制led硬件



 

首先介绍apk中使用jni中的几个接口

接口一: 调用动态库

             static{

              System.loadLibrary("led_jni"); // /system/lib/libled_jni.so

       }

接口二: 声明本地方法

              public native int OpenDev();

              public native int DevOn();

              public native int DevOff();

              public native int CloseDev();

接口三: 直接调用本地方方法

           OpenDev();

apk代码的内容如下,非常简单

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv* env = NULL;
jint ret = -1;
jint result = -1;

if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK) {
LOGE("ERROR: GetEnv failed");
goto bail;
}

ret = myRegisterNatives(env);
if(ret != JNI_TRUE)
{
LOGE("ERROR: registerNatives failed");
goto bail;

}
result = JNI_VERSION_1_4;

bail:
return result;

}


   vm->GetEnv((void **)&env, JNI_VERSION_1_4)该方法是dvm给我们提供的方法,用于获取环境变量对象JNIEnv* env,同时会检测jni的版本是否是1.4, 该方法正常返回JNI_OK

    myRegisterNatives(env);该法是自己去实现的,参数就是通过vm->GetENv方法获取的

b,
myRegisterNatives(env)的实现,主要是为了完成映射表的注册,会调用env->RegisterNatives()方法

static JNINativeMethod  myMethod[] ={
{"OpenDev", "()I", (void *)led_open},
{"DevOn", "()I", (void *)led_on},
{"DevOff", "()I", (void *)led_off},
{"DevClose", "()I", (void *)led_close},

};
 

第三个参数: 映射表表的成员个数sizeof(myMethods)/sizeof(myMethods[0])

返回: JNI_OnLoad正常 返回JNI_VERSION_1_4

         错误返回一个负数

c,接下来就是介绍映射表的构造了:

#define LOG_TAG "myledjni"
#include <utils/Log.h>

#include "jni.h"

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>

#define GPG3DAT2_ON _IO('L', 0x31)
#define GPG3DAT2_OFF _IO('L', 0x31)

static int fd = -1;
static jint led_open(JNIEnv *env, jobject obj)
{
//绯荤粺璋冪敤
LOGD("%s\n", __FUNCTION__);
fd = open("/dev/led", O_RDWR);
if(fd < 0)
{
LOGE("open dev error");
return -1;
}
return 0;
}

static jint led_on(JNIEnv *env, jobject obj)
{
LOGD("%s\n", __FUNCTION__);
int ret = -1;
ret = ioctl(fd,GPG3DAT2_ON,NULL);
if(ret < 0)
{
LOGE("ioctl error\n");
return -1;
}
return 0;
}

static jint led_off(JNIEnv *env, jobject obj)
{
LOGD("%s\n", __FUNCTION__);
int ret = -1;
ret = ioctl(fd,GPG3DAT2_OFF,NULL);
if(ret < 0)
{
LOGE("ioctl error\n");
return -1;
}

return 0;
}
static jint led_close(JNIEnv *env, jobject obj)
{
LOGD("%s\n", __FUNCTION__);
close(fd);
return 0;
}
static jint led_read(JNIEnv *env, jobject obj)
{
//read(fd, buf, size);
return 0 ;
}
static jint led_write(JNIEnv *env, jobject obj)
{
//write();
return 0 ;
}

static JNINativeMethod myMethod[] ={ {"OpenDev", "()I", (void *)led_open}, {"DevOn", "()I", (void *)led_on}, {"DevOff", "()I", (void *)led_off}, {"DevClose", "()I", (void *)led_close}, };

static char *clsStr = "fs/hq/LedActivity";

static int myRegisterNatives(JNIEnv* env)
{
jint ret = -1;
jclass myClz = env->FindClass(clsStr);
if (myClz == NULL) {
LOGE("Native registration unable to find class '%s'", clsStr);
return JNI_FALSE;
}

ret = env->RegisterNatives(myClz, myMethod, sizeof(myMethod)/sizeof(myMethod[0]));
if(ret < 0)
{
LOGE("%s, RegisterNatives failed", __FUNCTION__);
return JNI_FALSE;
}
LOGD("RegisterNatives Ok\n");

return JNI_TRUE;

}

jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint ret = -1; jint result = -1; if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK) { LOGE("ERROR: GetEnv failed"); goto bail; } ret = myRegisterNatives(env); if(ret != JNI_TRUE) { LOGE("ERROR: registerNatives failed"); goto bail; } result = JNI_VERSION_1_4; bail: return result; }
 

d,代码写好了,Android.mk是为了编译我们写的代码,代码最终会编译成动态库:

/*
* Simple - REALLY simple memory mapping demonstration.
*/

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>

#include <linux/kernel.h>   /* printk() */
#include <linux/slab.h>   /* kmalloc() */
#include <linux/fs.h>       /* everything... */
#include <linux/errno.h>    /* error codes */
#include <linux/types.h>    /* size_t */
#include <linux/mm.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#define pGPG3CON 0xE03001C0
#define pGPG3DAT 0xE03001C4
static void *vGPG3CON , *vGPG3DAT;
#define GPG3CON (*(volatile unsigned int *) vGPG3CON)
#define GPG3DAT (*(volatile unsigned int *) vGPG3DAT)
#define LED_ON   _IO('L', 0x31)
#define LED_OFF _IO('L', 0x30)

static int simple_major = 252;
module_param(simple_major, int, 0);
MODULE_AUTHOR("farsight");
MODULE_LICENSE("Dual BSD/GPL");

//static int flag = 0;

/*
* Open the device; in fact, there's nothing to do here.
*/
int simple_open (struct inode *inode, struct file *filp)
{
vGPG3CON=ioremap(pGPG3CON,0x10);
vGPG3DAT=vGPG3CON+0x04;
GPG3CON=0x1111;
//GPG3DAT=0xff;
return 0;
}

ssize_t simple_read(struct file *file, char __user *buff, size_t count, loff_t *offp)
{
return 0;
}

ssize_t simple_write(struct file *file, const char __user *buff, size_t count, loff_t *offp)
{
return 0;
}

void led_off( void )
{
GPG3DAT=GPG3DAT&(~(1<<2));

//printk("stop led\n");
}
void led_on( void )

{
GPG3DAT=GPG3DAT|(1<<2 printk="" start="" led="" n="" static="" int="" simple_ioctl="" struct="" inode="" inode="" struct="" file="" file="" unsigned="" int="" cmd="" unsigned="" long="" arg="" switch="" cmd="" case="" led_on:="" led_on="" break="" case="" led_off:="" led_off="" break="" default:="" break="" return="" 0="" static="" int="" simple_release="" struct="" inode="" node="" struct="" file="" file="" return="" 0="" set="" up="" the="" cdev="" structure="" for="" a="" device="" static="" void="" simple_setup_cdev="" struct="" cdev="" dev="" int="" minor="" struct="" file_operations="" fops="" int="" err="" devno="MKDEV(simple_major," minor="" cdev_init="" dev="" fops="" dev-="">owner = THIS_MODULE;
dev->ops = fops;
err = cdev_add (dev, devno, 1);
/* Fail gracefully if need be */
if (err)
printk (KERN_NOTICE "Error %d adding simple%d", err, minor);
}

/*
* Our various sub-devices.
*/
/* Device 0 uses remap_pfn_range */
static struct file_operations simple_remap_ops = {
.owner   = THIS_MODULE,
.open    = simple_open,
.release = simple_release,
.read    = simple_read,
.write   = simple_write,
.ioctl   = simple_ioctl,
};

/*
* We export two simple devices.  There's no need for us to maintain any
* special housekeeping info, so we just deal with raw cdevs.
*/
static struct cdev SimpleDevs;

/*
* Module housekeeping.
*/
static struct class *my_class;
static int simple_init(void)
{
int result;
dev_t dev = MKDEV(simple_major, 0);

/* Figure out our device number. */
if (simple_major)
result = register_chrdev_region(dev, 1, "simple");
else {
result = alloc_chrdev_region(&dev, 0, 1, "simple");
simple_major = MAJOR(dev);
}
if (result < 0) {
printk(KERN_WARNING "simple: unable to get major %d\n", simple_major);
return result;
}
if (simple_major == 0)
simple_major = result;

/* Now set up two cdevs. */
simple_setup_cdev(&SimpleDevs, 0, &simple_remap_ops);
printk("simple device installed, with major %d\n", simple_major);
my_class= class_create(THIS_MODULE, "simple");
device_create(my_class, NULL, MKDEV(simple_major, 0),
NULL, "led");
return 0;
}

static void simple_cleanup(void)
{
cdev_del(&SimpleDevs);
unregister_chrdev_region(MKDEV(simple_major, 0), 1);
device_destroy(my_class,MKDEV(simple_major,0));
printk("simple device uninstalled\n");
}

module_init(simple_init);
module_exit(simple_cleanup);
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: