android led hal实践

一、编写linux驱动

------s5pv210_leds.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/device.h>
#include <linux/cdev.h>

#define S5PV210_GPJ2CON 0
#define S5PV210_GPJ2DAT 1

volatile unsigned int *gpj2con = NULL;
volatile unsigned int *gpj2dat= NULL;
static unsigned int mem[2]; 
static dev_t devno;
static struct class *leds_class = NULL;
 
static ssize_t leds_hal_write(struct file *file, const char __user *buf,size_t count, loff_t *ppos)
{
	if (copy_from_user(mem, buf, count))	//成功返回0,失败返回没拷贝的字节数
	{
		return -EFAULT;
	}
	else
	{
		switch (buf[0])
		{
			case S5PV210_GPJ2CON:
				*gpj2con=mem[1];
				printk("gpj2con=%u\n",*gpj2con);
				break;
			case S5PV210_GPJ2DAT:
				*gpj2dat=mem[1];
				printk("gpj2dat:%u\n",*gpj2dat);
				break;
		}

	}
	return count;
}

static struct file_operations dev_fops =
{ 
	.owner = THIS_MODULE, 
	.write = leds_hal_write,
};
static struct cdev cdev;

static int leds_init(void)
{
	cdev_init(&cdev, &dev_fops);
	cdev.owner = THIS_MODULE;
	alloc_chrdev_region(&devno, 0, 1,"lyl_hal_leds");
	cdev_add(&cdev, devno, 1);
	
	leds_class = class_create(THIS_MODULE, "lyl_hal_leds");
	device_create(leds_class, NULL, devno, NULL, "lyl_hal_leds");
	
	gpj2con = (volatile unsigned int*)ioremap(0xe0200280, 8);
	gpj2dat = gpj2con + 1;
	printk("leds_init\n");
	return 0;
}

static void leds_exit(void)
{
	device_destroy(leds_class, devno);
	class_destroy(leds_class);
	unregister_chrdev_region(devno, 0);
	cdev_del(&cdev);
	iounmap(gpj2con);
	printk("leds_exit\n");
}

module_init(leds_init);
module_exit(leds_exit);
MODULE_LICENSE("GPL");
------Makefile
KERN_DIR = /home/linux-3.0.8
all:
	make -C $(KERN_DIR) M=`pwd` modules 
clean:
	make -C $(KERN_DIR) M=`pwd` modules clean
	rm -rf modules.order
obj-m	+= s5pv210_leds.o
------wdev.c
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/ioctl.h>

int main(int argc,char**argv)
{
	int fd=0;
	unsigned int buf[2];
	buf[0]=atoi(argv[1]);
	buf[1]=atoi(argv[2]);
	fd=open("/dev/lyl_hal_leds",O_RDWR);
	if(fd<0)
	{
		printf("open error\n");
		return -1;
	}
	write(fd,buf,sizeof(buf));
	close(fd);
	return 0;
}
------测试linux驱动
root@lyl:/home/test# ls
Makefile  s5pv210_leds.c  wdev.c
root@lyl:/home/test# make
root@lyl:/home/test# arm-linux-gcc -static wdev.c -o wdev //必须静态编译
root@lyl:/home/test# adb push s5pv210_leds.ko /data/local/
root@lyl:/home/test# adb push wdev /data/local/
root@lyl:/home/test# adb shell
/data/local # insmod s5pv210_leds.ko
/data/local # ./wdev 0 4369
/data/local # ./wdev 1 0 //led全点亮,说明linux驱动正常

二、编写HAL library

------leds_hal.c
#include "leds_hal.h"

static int dev_file=0;
static int led_on(struct led_control_device_t*dev,int led)
{
	unsigned int buf[2];
	buf[0]=0;
	buf[1]=4369;
	write(dev_file,buf,sizeof(buf));
	if(led>=0&&led<=3)
	{
		buf[0]=1;
		switch(led)
		{
			case 0:
				buf[1]=14;
				LOGI("led 0 on");
				break;
			case 1:
				LOGI("led 1 on");
				buf[1]=13;
				break;
			case 2:
				LOGI("led 2 on");
				buf[1]=11;
				break;
			case 3:
				LOGI("led 3 on");
				buf[1]=7;
				break;
		}
		write(dev_file,buf,sizeof(buf));
	}
	else
	{
		LOGI("LED Stub:set led %d on error,no this led",led);
	}
	return 0;
}

static int led_device_close(struct hw_device_t*device)
{
	struct led_control_device_t*ctx=(struct led_control_device_t*)device;
	if(ctx)
	{
		free(ctx);
	}
	close(dev_file);
	return 0;
}

static int led_device_open(const struct hw_module_t*module,const char*name,struct hw_device_t**device)
{
	struct led_control_device_t *dev=(struct led_control_device_t*)malloc(sizeof(*dev));
	if(dev==NULL)
	{
		LOGI("malloc led_control_device_t fail");
		return -1;
	}
	else
	{
		LOGI("malloc led_control_device_t success\n");
	}
	memset(dev,0,sizeof(*dev));
	dev->hw_device.tag=HARDWARE_DEVICE_TAG;		//值固定
	dev->hw_device.version=0;
	dev->hw_device.module=(struct hw_module_t*)module;
	dev->hw_device.close=led_device_close;
	dev->set_on=led_on;
	*device=&dev->hw_device;
	dev_file=open(DEVICE,O_RDWR);
	if(dev_file<0)
	{
		LOGI("LED Stub:open /dev/lyl_leds_hal fail");
		return -1;
	}
	else
	{
		LOGI("LED Stub:open /dev/lyl_leds_hal success.");
	}
	return 0;
}

static struct hw_module_methods_t led_module_methods=
{
	open:led_device_open,
};

struct led_module_t HAL_MODULE_INFO_SYM=
{
	hw_module:
	{
		tag:HARDWARE_MODULE_TAG,	//值固定
		version_major:1,
		version_minor:0,
		id:LED_HARDWARE_MODULE_ID,	//通过该id找到HAL模块
		name:"lyl_leds_hal",
		author:"liyanlong",
		methods:&led_module_methods,
	},
};
------leds_hal.h
#include <hardware/hardware.h>
#include <fcntl.h>
#include <cutils/log.h>

struct led_module_t	//不能直接使用hw_module_t结构体
{
	struct hw_module_t hw_module;	//必须为第一个成员
};

struct led_control_device_t
{
	struct hw_device_t hw_device;	//必须为第一个成员
	int (*set_on)(struct led_control_device_t*dev,int led);
};

#define LED_HARDWARE_MODULE_ID "led_hal"
#define DEVICE "/dev/lyl_hal_leds"
------Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(PWD)/
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := leds_hal.c
LOCAL_MODULE := led_hal.default
	#id必须为LED_HARDWARE_MODULE_ID
LOCAL_MODULE_TAGS := eng
include $(BUILD_SHARED_LIBRARY)
------编译
root@lyl:/test/android-4.0.3# . build/envsetup.sh
root@lyl:/test/android-4.0.3# lunch 1
root@lyl:/test/android-4.0.3/hardware/hal# ls
Android.mk  leds_hal.c  leds_hal.h
root@lyl:/test/android-4.0.3/hardware/hal# mm
root@lyl:/test/android-4.0.3/hardware/hal# adb push led_hal.default.so /system/lib/hw/

三、编写JNI library

------LedHalService.cpp
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <jni.h>
#include "leds_hal.h"

struct led_control_device_t *led_hal_device;
static jboolean led_setOn(JNIEnv*env,jobject thiz,jint led)
{
	if(led_hal_device==NULL)
	{
		LOGI("led_hal_device was not fetched correctly.");
		return -1;
	}
	else
	{
		return led_hal_device->set_on(led_hal_device,led);
	}
}

static jboolean led_init(JNIEnv*env,jclass clazz)
{
	led_module_t *module;
	if(hw_get_module(LED_HARDWARE_MODULE_ID,(const struct hw_module_t **)&module)==0)
	{
		return module->hw_module.methods->open((const struct hw_module_t*)module,LED_HARDWARE_MODULE_ID,(struct hw_device_t**)&led_hal_device);
	}
	LOGI("Get stub operations failed.");
	return -1;
}

static const JNINativeMethod methods[]=	//函数映射
{
		{"_init","()Z",(void*)led_init},
		{"_set_on","(I)Z",(void*)led_setOn},
};

int register_led_hal_jni(JNIEnv*env)
{
	static const char*const kClassName="lyl/leds/hal/LedHalService";	//由该类调用当前JNI库
	jclass clazz;
	clazz=env->FindClass(kClassName);
	if(clazz==NULL)
	{
		LOGE("can not find class %s",kClassName);
		return -1;
	}
	if(env->RegisterNatives(clazz,methods,sizeof(methods)/sizeof(methods[0]))!=JNI_OK)
	{
		LOGE("failed registering methods for %s",kClassName);
		return -1;
	}
	return 0;
}

jint JNI_OnLoad (JavaVM*vm,void*reserved)	//装载该库后自动调用JNI_OnLoad函数
{
	JNIEnv*env=NULL;
	jint result=-1;
	if(vm->GetEnv((void**)&env,JNI_VERSION_1_4)!=JNI_OK)
	{
		LOGE("GetEnv failed!");
		return result;
	}
	register_led_hal_jni(env);
	return JNI_VERSION_1_4;
}
------Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(PWD)/
LOCAL_SHARED_LIBRARIES := libandroid_runtime libcutils libhardware libhardware_legacy \
	libnativehelper libsystem_server libutils libui 
LOCAL_C_INCLUDES += $(PWD)/
LOCAL_SRC_FILES := LedHalService.cpp
LOCAL_MODULE := jni
LOCAL_MODULE_TAGS := eng
include $(BUILD_SHARED_LIBRARY)
------编译
root@lyl:/test/android-4.0.3/hardware/jni# ls
Android.mk  LedHalService.cpp  leds_hal.h
root@lyl:/test/android-4.0.3/hardware/jni# mm
root@lyl:/test/android-4.0.3/hardware/jni# adb push jni.so /system/lib/

四、编写android APP

------LedServer.java
package lyl.leds.hal;
import android.R.bool;
public class LedHalService {
	private static LedHalService halService;
	public static LedHalService getInstance(){
		if(halService==null){
			return new LedHalService();
		}else{
			return halService;
		}
	}
	private LedHalService() {
		_init();
	}
	public boolean setOn(int led){
		return _set_on(led);
	}
	private native boolean _init();
	private native boolean _set_on(int led);
	static{
		System.load("/system/lib/jni.so");
	}
}
------MainActivity.java
package lyl.leds.hal;
import lyl.leds.service.R;
import android.app.Activity;
import android.os.Bundle;
import android.widget.RadioButton;
import android.widget.RadioGroup;
public class MainActivity extends Activity {
	LedHalService halService=LedHalService.getInstance();
	private RadioGroup ledGroup = null;
	private RadioButton led0 = null;
	private RadioButton led1 = null;
	private RadioButton led2 = null;
	private RadioButton led3 = null;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		ledGroup=(RadioGroup)findViewById(R.id.led);
		led0=(RadioButton)findViewById(R.id.led0);
		led1=(RadioButton)findViewById(R.id.led1);
		led2=(RadioButton)findViewById(R.id.led2);
		led3=(RadioButton)findViewById(R.id.led3);
		ledGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
			@Override
			public void onCheckedChanged(RadioGroup group, int checkedId) {
				if(led0.getId() == checkedId){
					halService.setOn(0);
				}
				else if(led1.getId() == checkedId)
				{
					halService.setOn(1);
				}
				else if(led2.getId()==checkedId){
					halService.setOn(2);
				}
				else if(led3.getId()==checkedId){
					halService.setOn(3);
				}
			}
		});
	}
}
------activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
	<RadioGroup
		android:id="@+id/led"
	    android:layout_width="wrap_content" 
	    android:layout_height="wrap_content" 
	    android:orientation="vertical">

		<RadioButton
	    	android:id="@+id/led0"
	 	    android:layout_width="wrap_content" 
	  	    android:layout_height="wrap_content" 
	  	    android:text="led0"
	  	    />
	    <RadioButton
	    	android:id="@+id/led1"
	 	    android:layout_width="wrap_content" 
	  	    android:layout_height="wrap_content" 
	  	    android:text="led1"
	  	    />
	    <RadioButton
	    	android:id="@+id/led2"
	 	    android:layout_width="wrap_content" 
	  	    android:layout_height="wrap_content" 
	  	    android:text="led2"
	  	    />
	    <RadioButton
	    	android:id="@+id/led3"
	 	    android:layout_width="wrap_content" 
	  	    android:layout_height="wrap_content" 
	  	    android:text="led3"
  	    />
	</RadioGroup> 
</LinearLayout>
------测试
root@lyl:/home# adb push leds_hal.apk /mnt/sdcard/
/mnt/sdcard # adb install leds_hal.apk
/data/local # chmod 777 /dev/lyl_hal_leds
点击LCD屏单选按钮即可点亮相应LED
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值