基于TINY4412的Andorid开发-------简单的LED灯控制
阅读目录(Content)
- 一、编写驱动程序
- 二、编写代码测试驱动程序
- 三、编写HAL代码
- 四、编写Framework代码
- 五、编写JNI代码
- 六、编写App
参考资料:
《Andriod系统源代码情景分析》
《嵌入式Linux系统开发完全手册_基于4412_上册》
作者:彭东林
邮箱:pengdonglin137@163.com
平台介绍:
主机:Win7 32位
虚拟机:VMware10 + ubuntu-12.04.2-desktop-amd64
Android版本: android-4.2.2_r1
Linux内核版本:linux-3.5.0
Bootloader: 友善之臂提供的Superboot4412.bin
目标平台:tiny4412ADK+S700 4GB Flash
目的: 在Tiny4412上运行的Android系统上,通过点击屏幕上的Button来控制Tiny4412的核心板上的四个LED灯的亮灭。一个有八个Button,每个灯的亮灭通过两个灯来控制,点击ON,相应的LED亮;点击OFF,相应的LED灯灭。
下面分几步完成:
1、编写驱动程序
2、测试驱动程序
3、编写HAL代码
4、编写framework代码
5、编写JNI代码
6、编写App
下面开始:
回到顶部(go to top)
一、编写驱动程序
分析tiny4412的原理图,看一下LED灯的位置:
可以知道,LED是低电平亮,高电平灭。
看一下,接到了Exynos4412的哪些引脚上了:
可以看到:
LED1 --------- GPM4_0
LED2 --------- GPM4_1
LED3 --------- GPM4_2
LED4 --------- GPM4_3
看一下Exynos4412的芯片手册,看一下GPM4的相关寄存器:
图中第二列表示的相对于基地址的偏移量,这里基地址是:0x11000000.
在芯片手册的Page288 ~ Page291对这些寄存器有更详细的介绍。
以GPM4_0引脚为例:
为了控制灯,[3:0]应设置为0x01,即输出模式
向GPM4DAT的第0位写0,GPM4_0引脚输出低电平,LED1亮;
向GPM4DAT的第0位写1,GPM4_0引脚输出高电平,LED1灭;
接下来,开始写驱动程序,用友善之臂自带的Linux3.5.0内核
1: cd linux-3.5/
2: cd drivers/
3: mkdir android_led
4: cd android_led/
在android_led/下创建led_demo.c和led_demo.h文件:
touch led_demo.c led_demo.h
再在其中创建Makefile和Kconfig文件
touch Makefile Kconfig
- 修改Kconfig:
1: config LED_DEMO 2: tristate "Android Led Demo" 3: default n 4: help 5: This is the led demo for Android system.
- 修改Makefile:
obj-$(CONFIG_LED_DEMO) += led_demo.o
- 修改drivers/Kconfig,添加 source “drivers/android_led/Kconfig”
1: menu "Device Drivers" 2: 3: source "drivers/android_led/Kconfig" 4: 5: ...... 6: 7: endmenu
- 修改drivers/Makefile:
1: ...... 2: 3: obj-$(CONFIG_LED_DEMO) += android_led/
- 在内核顶层目录下执行make menuconfig,进入Device Drivers,将 Android Led Demo选择为*,然后保存配置退出。
-
注:执行上面这些操作之前,确保已经按照友善之臂的手册,成功编译了Android上用的Linux内核,并且在arch/arm/boot下生成了zImage等文件。
在前期开发的时候,时不时要编译,可以将drivers/android_led/Makefile修改为:
1: #obj-$(CONFIG_LED_DEMO) += led_demo.o 2: obj-m += led_demo.o
编译的时候,可以使用:
make M=drivers/android_led modules
-
目的是提高编译速度,最后再将Makfile改回原样。临时测试,可以在Wind7的命令行下,使用adb push将led_demo.ko上传到/data/local下,然后用adb shell登陆板子,进行测试。
- 修改led_demo.h和led_demo.c
-
led_demo.h:
1: #ifndef __LED_DEMO_H__ 2: #define __LED_DEMO_H__ 3: 4: #include <linux/cdev.h> 5: 6: #define LED_ON _IOW('L', 0, int) 7: #define LED_OFF _IOW('L', 1, int) 8: 9: #define LED_DEMO_DEVICE_NODE_NAME "led_demo" 10: #define LED_DEMO_DEVICE_CLASS_NAME "led_demo" 11: #define LED_DEMO_DEVICE_FILE_NAME "led_demo" 12: 13: #define EXYNOS4412_GPM4CON 0x110002E0 14: #define EXYNOS4412_GPM4DAT 0x110002E4 15: 16: 17: struct led_demo_dev 18: { 19: struct cdev dev; 20: }; 21: 22: #endif
led_demo.c:
1: #include <linux/kernel.h> 2: #include <linux/module.h> 3: #include <linux/fs.h> 4: #include <linux/slab.h> 5: #include <linux/device.h> 6: 7: #include <asm/io.h> 8: #include <asm/uaccess.h> 9: 10: 11: #include "led_demo.h" 12: 13: 14: MODULE_LICENSE("GPL"); 15: 16: 17: static int led_demo_major; 18: static int led_demo_minor; 19: static int number_of_dev = 1; 20: 21: static struct led_demo_dev *led_dev = NULL; 22: 23: static unsigned int *GPM4CON = NULL; 24: static unsigned int *GPM4DAT = NULL; 25: 26: static struct class *led_demo_class = NULL; 27: 28: 29: static int led_open (struct inode *node, struct file *fops) 30: { 31: struct led_demo_dev *dev; 32: 33: dev = container_of(node->i_cdev, struct led_demo_dev, dev); 34: 35: fops->private_data = dev; 36: 37: return 0; 38: } 39: static int led_close (struct inode *node, struct file *fops) 40: { 41: return 0; 42: } 43: 44: static long led_ioctl (struct file *fops, unsigned int cmd, unsigned long data) 45: { 46: //struct led_demo_dev * led_dev = (struct led_demo_dev *)fops->private_data; 47: 48: if((data < 1) || (data > 4)) 49: { 50: printk(KERN_ALERT"parameter is no valid.\n"); 51: return -EINVAL; 52: } 53: 54: switch (cmd) 55: { 56: case LED_OFF: 57: writel(readl(GPM4DAT) | (0x1<<(data-1)), GPM4DAT); 58: break; 59: case LED_ON: 60: writel(readl(GPM4DAT) & ~(0x1<<(data-1)), GPM4DAT); 61: break; 62: default: 63: return -EINVAL; 64: break; 65: } 66: 67: 68: return 0; 69: } 70: 71: struct file_operations led_fops = 72: { 73: .owner = THIS_MODULE, 74: .open = led_open, 75: .unlocked_ioctl = led_ioctl, 76: .compat_ioctl = led_ioctl, 77: .release = led_close, 78: }; 79: 80: static int __led_setup_dev(struct led_demo_dev * dev) 81: { 82: int err = -1; 83: 84: dev_t devno = MKDEV(led_demo_major, led_demo_minor); 85: 86: memset(dev, 0, sizeof(struct led_demo_dev)); 87: 88: cdev_init(&(dev->dev), &led_fops); 89: 90: dev->dev.owner = THIS_MODULE; 91: 92: err = cdev_add(&(dev->dev), devno, number_of_dev); 93: if(err < 0) 94: { 95: return err; 96: } 97: 98: return 0; 99: } 100: 101: static int led_demo_init(void) 102: { 103: int err = -1; 104: dev_t dev; 105: struct device *temp = NULL; 106: 107: printk(KERN_ALERT"Initializing led demo device.\n"); 108: 109: err = alloc_chrdev_region(&dev, 0, number_of_dev, LED_DEMO_DEVICE_NODE_NAME); 110: if(err < 0) 111: { 112: printk(KERN_ALERT"fail to alloc char dev region.\n"); 113: goto fail; 114: } 115: 116: led_demo_major = MAJOR(dev); 117: led_demo_minor = MINOR(dev); 118: 119: led_dev = kmalloc(sizeof(struct led_demo_dev), GFP_KERNEL); 120: if(!led_dev) 121: { 122: err = -ENOMEM; 123: printk(KERN_ALERT"Failed to alloc led device.\n"); 124: goto unregister; 125: } 126: 127: err = __led_setup_dev(led_dev); 128: if (err < 0) 129: { 130: printk(KERN_ALERT"Failed to setup led device.\n"); 131: goto clean_up; 132: } 133: 134: GPM4CON = (unsigned int *)ioremap(EXYNOS4412_GPM4CON, 4); 135: if(!GPM4CON) 136: { 137: err = -ENOMEM; 138: goto destroy_cdev; 139: } 140: 141: GPM4DAT = (unsigned int *)ioremap(EXYNOS4412_GPM4DAT, 4); 142: if(!GPM4DAT) 143: { 144: err = -ENOMEM; 145: goto unmap1; 146: } 147: 148: writel((readl(GPM4CON) & ~0xffff) | 0x1111, GPM4CON); 149: writel(readl(GPM4DAT)| 0xf, GPM4DAT); 150: 151: led_demo_class = class_create(THIS_MODULE, LED_DEMO_DEVICE_CLASS_NAME); 152: if(IS_ERR(led_demo_class)) 153: { 154: err = PTR_ERR(led_demo_class); 155: printk(KERN_ALERT"Failed to create led demo class.\n"); 156: goto unmap2; 157: } 158: 159: temp = device_create(led_demo_class, NULL, dev, NULL, "%s", LED_DEMO_DEVICE_FILE_NAME); 160: if(IS_ERR(temp)) 161: { 162: err = PTR_ERR(temp); 163: printk(KERN_ALERT"Failed to create led demo device.\n"); 164: goto destroy_class; 165: } 166: 167: dev_set_drvdata(temp, (void *)led_dev); 168: 169: printk(KERN_ALERT"Succeed to initialize led demo device.\n"); 170: 171: return 0; 172: 173: destroy_class: 174: class_destroy(led_demo_class); 175: 176: unmap2: 177: iounmap(GPM4DAT); 178: 179: unmap1: 180: iounmap(GPM4CON); 181: 182: destroy_cdev: 183: cdev_del(&(led_dev->dev)); 184: 185: clean_up: 186: kfree(led_dev); 187: 188: unregister: 189: unregister_chrdev_region(MKDEV(led_demo_major, led_demo_minor), number_of_dev); 190: 191: fail: 192: 193: return err; 194: } 195: 196: static void led_demo_exit(void) 197: { 198: if(led_demo_class) 199: { 200: device_destroy(led_demo_class, MKDEV(led_demo_major, led_demo_minor)); 201: class_destroy(led_demo_class); 202: } 203: 204: iounmap(GPM4DAT); 205: iounmap(GPM4CON); 206: 207: if(led_dev) 208: { 209: cdev_del(&(led_dev->dev)); 210: kfree(led_dev); 211: } 212: 213: unregister_chrdev_region(MKDEV(led_demo_major, led_demo_minor), number_of_dev); 214: } 215: 216: 217: 218: module_init(led_demo_init); 219: module_exit(led_demo_exit); 220:
编写完成后,在内核源码的顶层目录执行make zImage –jN,然后就会在arch/arm/boot/生成zImage文件,利用友善之臂提供的Minitools将zImage烧写到板子上。具体步骤,参考友善之臂提供的PDF文档:《Tiny4412用户手册》
回到顶部(go to top)
二、编写代码测试驱动程序
在android-4.2.2_r1源码顶层目录下
1: external/led_demo/ 2: ├── Android.mk 3: ├── led_demo.c 4: └── led_demo.h
即,在external/下创建led_demo目录,并在其中创建Android.mk、led_demo.c以及led_demo.h文件.
Android.mk:
1: LOCAL_PATH:= $(call my-dir) 2: include $(CLEAR_VARS) 3: LOCAL_MODULE_TAGS := optional 4: LOCAL_SRC_FILES := $(call all-subdir-c-files) 5: LOCAL_MODULE := led_demo_test 6: include $(BUILD_EXECUTABLE) 7:
led_demo.h:
1: #ifndef __LED_DEMO_H__ 2: #define __LED_DEMO_H__ 3: 4: #define LED_ON _IOW('L', 0, int) 5: #define LED_OFF _IOW('L', 1, int) 6: 7: #endif
led_demo.c:
1: #include <stdio.h> 2: #include <sys/types.h> 3: #include <sys/stat.h> 4: #include <fcntl.h> 5: #include <stdlib.h> 6: #include <sys/ioctl.h> 7: 8: #include "led_demo.h" 9: 10: int main(int argc, const char *argv[]) 11: { 12: int fd; 13: int i; 14: 15: fd = open("/dev/led_demo", O_RDWR); 16: if (fd < 0) 17: { 18: perror("failed to open.\n"); 19: exit(-1); 20: } 21: 22: while(1) 23: { 24: for(i=0; i<4; i++) 25: { 26: ioctl(fd, LED_OFF, i+1); 27: sleep(1); 28: ioctl(fd, LED_ON, i+1); 29: sleep(1); 30: ioctl(fd, LED_OFF, i+1); 31: sleep(1); 32: } 33: } 34: 35: close(fd); 36: 37: return 0; 38: } 编写完成后,在android-4.2.2_r1源码顶层目录下执行: 1: mmm ./external/led_demo/ 2: 3: ./gen-img.sh
然后将顶层目录下新生成的system.img利用友善之臂提供的Minitools烧写到板子上。
烧写完成后,重启板子。
使用串口终端登陆板子,使用su命令进入root用户模式,然后进入/system/bin目录下,执行./led_demo_test,观察现象,可以看到,TINY4412的核心板上的四个LED灯循环亮灭。也可以使用wind7下的控制终端,用adb shell登陆板子,进行测试。
回到顶部(go to top)
三、编写HAL代码
在hardware/libhardware/include/hardware/下创建文件led_demo_hal.h
在hardware/libhardware/modules/下创建目录led_demo_hal,然后进入led_demo_hal,创建两个文件,分别是Android.mk和
led_demo_hal.cpp。
下面是文件内容:
hardware/libhardware/include/hardware/led_demo_hal.h
-
1: #ifndef ANDROID_LED_DEMO_HAL_H 2: #define ANDROID_LED_DEMO_HAL_H 3: 4: #include <hardware/hardware.h> 5: 6: __BEGIN_DECLS 7: 8: #define LED_DEMO_HARDWARE_MODULE_ID "led_demo_hal" //模块ID 需要与下面的Android.mk中的LOCAL_MODULE 匹配,否则无法加载该HAL模块 9: #define LED_DEMO_HARDWARE_DEVICE_ID "led_demo" // 设备ID 10: 11: 12: struct led_demo_module_t 13: { 14: struct hw_module_t common; 15: }; 16: 17: struct led_demo_device_t 18: { 19: struct hw_device_t common; 20: int fd; 21: int (*set_on)(struct led_demo_device_t *dev, int val); //用于控制LED,点亮第val个LED灯 22: int (*set_off)(struct led_demo_device_t *dev, int val); //熄灭第val个LED灯 23: }; 24: 25: __END_DECLS 26: 27: 28: #endif hardware/libhardware/modules/led_demo_hal/led_demo_hal.cpp 1: #define LOG_TAG "LED_DEMO_HALSTUB" //将来可以用DDMS的LogCat工具进行调试,便于查看打印信息 2: 3: #include <hardware/hardware.h> 4: #include <hardware/led_demo_hal.h> 5: 6: #include <fcntl.h> 7: #include <errno.h> 8: 9: #include <utils/Log.h> 10: #include <cutils/atomic.h> 11: 12: 13: #define DEVICE_NAME "/dev/led_demo" //设备结点,有Linux驱动程序自动创建 14: #define MODULE_NAME "led_demo" 15: #define MODULE_AUTHOR "pengdonglin137@163.com" 16: 17: #define LED_ON 0x40044c00 //点灯的命令,其实就是_IOW('L', 0, int)的值,_IOW在编译时无法识别,待以后解决 18: #define LED_OFF 0x40044c01 //灭灯命令,其实就是_IOW('L', 1, int)的值,可以在上面的led_demo.c中加打印,看一下这个值是多少 19: 20: 21: static int led_demo_open(const struct hw_module_t* module, const char* id, 22: struct hw_device_t** device); 23: 24: static int led_demo_close(struct hw_device_t* device); 25: 26: static int led_demo_set_on(struct led_demo_device_t *dev, int val); 27: 28: static int led_demo_set_off(struct led_demo_device_t *dev, int val); 29: 30: 31: static hw_module_methods_t led_demo_module_methods = 32: { 33: open:led_demo_open, 34: }; 35: 36: struct led_demo_module_t HAL_MODULE_INFO_SYM = 37: { 38: common:{ 39: tag:HARDWARE_MODULE_TAG, 40: version_major:1, 41: version_minor:0, 42: id:LED_DEMO_HARDWARE_MODULE_ID, 43: name:MODULE_NAME, 44: author:MODULE_AUTHOR, 45: methods:&led_demo_module_methods, 46: } 47: }; 48: 49: static int led_demo_open(const struct hw_module_t* module, const char* id, 50: struct hw_device_t** device) 51: { 52: if(!strcmp(id, LED_DEMO_HARDWARE_DEVICE_ID)) 53: { 54: struct led_demo_device_t *dev; 55: 56: dev = (struct led_demo_device_t *)malloc(sizeof(struct led_demo_device_t)); 57: if(!dev) 58: { 59: ALOGE("Failed to alloc space for struct led_demo_device_t."); 60: return -EFAULT; 61: } 62: 63: memset(dev, 0, sizeof(struct led_demo_device_t)); 64: 65: dev->common.tag =
HARDWARE_DEVICE_TAG
; 66: dev->common.version = 0; 67: dev->common.module = (struct hw_module_t *)module; 68: dev->common.close = led_demo_close; 69: dev->set_on = led_demo_set_on; 70: dev->set_off = led_demo_set_off; 71: 72: if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) 73: { 74: ALOGE("Failed to open device %s ---- %s\n.", DEVICE_NAME, strerror(errno)); 75: free(dev); 76: return -EFAULT; 77: } 78: 79: *device = &(dev->common); 80: 81: ALOGE("Open device file %s successfully.", DEVICE_NAME); 82: 83: } 84: 85: return -EFAULT; 86: } 87: 88: static int led_demo_close(struct hw_device_t* device) 89: { 90: struct led_demo_device_t *led_device = (struct led_demo_device_t *)device; 91: if(led_device) 92: { 93: close(led_device->fd); 94: free(led_device); 95: } 96: 97: return 0; 98: } 99: 100: static int led_demo_set_on(struct led_demo_device_t *dev, int val) 101: { 102: if(!dev) 103: { 104: ALOGE("Null dev pointer."); 105: return -EFAULT; 106: } 107: 108: if(ioctl(dev->fd, LED_ON, val) < 0) 109: { 110: ALOGE("ioctl error --- %s.", strerror(errno)); 111: return -EFAULT; 112: } 113: 114: return 0; 115: 116: } 117: 118: static int led_demo_set_off(struct led_demo_device_t *dev, int val) 119: { 120: if(!dev) 121: { 122: ALOGE("Null dev pointer."); 123: return -EFAULT; 124: } 125: 126: if(ioctl(dev->fd, LED_OFF, val) < 0) 127: { 128: ALOGE("ioctl error --- %s.", strerror(errno)); 129: return -EFAULT; 130: } 131: 132: return 0; 133: 134: } 135: hardware/libhardware/modules/led_demo_hal/Android.mk 1: LOCAL_PATH := $(call my-dir) 2: include $(CLEAR_VARS) 3: LOCAL_MODULE_TAGS := optional 4: LOCAL_PRELINK_MODULE := false 5: LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw 6: LOCAL_SHARED_LIBRARIES := liblog 7: LOCAL_SRC_FILES := led_demo_hal.cpp 8: LOCAL_MODULE := led_demo_hal.default 9: include $(BUILD_SHARED_LIBRARY)
编写完成后,在Android源码的顶层目录执行:
mmm ./hardware/libhardware/modules/led_demo_hal/
终out/target/product/tiny4412/system/lib/hw/目录下得到一个led_demo_hal.default.so文件。
下面处理一下硬件设备访问权限问题
在硬件抽象层模块中,我们是调用open函数来打开对应的设备文件的,在默认情况下,只有root用户才有权限访问系统的设备文件。但是一般的应用程序是没有root用户权限的。
解决办法,赋予root之外的其他用户访问设别文件/dev/led_demo的权限。做法如下:
在Android源码顶层目录下,修改system/core/rootdir/ueventd.rc,添加如下内容:
/dev/led_demo 0666 root root
修改了ueventd.rc文件后,需要重新编译Android源代码工程,编译时,文件system/core/rootdir/ueventd.rc会拷贝到out/target/product/tiny4412/root/下,并且最终打包在ramdisk.img中。对于友善之臂,执行完make -jN后,还需要执行./gen-img.sh脚本,然后在Android源码顶层目录中会生成ramdisk-u.img文件,利用MiniTools将其烧写到板子上。
回到顶部(go to top)
四、编写Framework代码
- 定义硬件访问服务接口
-
在frameworks/base/core/java/android/os/创建文件ILed_demo_service.aidl,内容如下:
1: package android.os; 2: 3: interface ILed_demo_service 4: { 5: void led_set_ON(int val); 6: void led_set_OFF(int val); 7: } 然后,修改frameworks/base/Android.mk 1: LOCAL_SRC_FILES += \ 2: ...... 3: core/java/android/os/IVibratorService.aidl \ 4: core/java/android/os/ILed_demo_service.aidl \
最后,在Android源码顶层目录下执行
mmm ./frameworks/base/
编译后得到的framework.jar文件就包含了ILed_demo_service接口。
- 实现硬件访问服务
-
在frameworks/base/services/java/com/android/server/创建文件Led_demo_Service.java,内容如下:
1: package com.android.server; 2: import android.content.Context; 3: import android.os.ILed_demo_service; 4: import android.util.Slog; 5: 6: 7: public class Led_demo_Service extends ILed_demo_service.Stub 8: { 9: private static final String TAG = "Led_demo_Service"; //方便DDMS提供的LogCat工具看打印信息 10: 11: private int mPtr = 0; 12: 13: Led_demo_Service() 14: { 15: mPtr = init_native(); //硬件访问服务Led_demo_Service在启动时,会通过JNI方法init_native 16: 17: if(mPtr == 0) 18: { 19: Slog.e(TAG, "Failed to initialize Led demo Service."); 20: } 21: } 22: 23: public void led_set_ON(int val) 24: { 25: if(mPtr == 0) 26: { 27: Slog.e(TAG, "Led demo Service is not initialized."); 28: return; 29: } 30: 31: set_ON_native(mPtr, val); 32: } 33: 34: public void led_set_OFF(int val) 35: { 36: if(mPtr == 0) 37: { 38: Slog.e(TAG, "Led demo Service is not initialized."); 39: return; 40: } 41: 42: set_OFF_native(mPtr, val); 43: } 44: 45: 46: private static native int init_native(); 47: private static native void set_OFF_native(int mPtr, int val); 48: private static native void set_ON_native(int mPtr, int val); 49: 50: 51: };
编写完成后,在Android源码顶层目录下执行:
mmm ./frameworks/base/services/java/
编译后得到的services.jar文件就包含有Led_demo_Service类。
-
回到顶部(go to top)
五、编写JNI代码
在frameworks/base/services/jni/下创建文件com_android_server_led_demo_service.cpp,内容如下:
1: #define LOG_TAG "LED_DEMO_Service_JNI" //方便LogCat调试工具查看打印信息 2: 3: #include "jni.h" 4: #include "JNIHelp.h" 5: #include "android_runtime/AndroidRuntime.h" 6: 7: #include <utils/misc.h> 8: #include <utils/Log.h> 9: #include <hardware/hardware.h> 10: #include <hardware/led_demo_hal.h> 11: 12: #include <stdio.h> 13: 14: 15: namespace android 16: { 17: 18: static void led_demo_setOFF(JNIEnv *env, jobject clazz, jint ptr, jint value) 19: { 20: led_demo_device_t *device = (led_demo_device_t *)ptr; 21: if(!device) 22: { 23: ALOGE("Device led demo is not open."); 24: return ; 25: } 26: 27: int val = value; 28: 29: ALOGI("Set value %d to device led demo.", val); 30: 31: device->set_off(device, value); 32: } 33: 34: static void led_demo_setON(JNIEnv *env, jobject clazz, jint ptr, jint value) 35: { 36: led_demo_device_t *device = (led_demo_device_t *)ptr; 37: if(!device) 38: { 39: ALOGE("Device led demo is not open."); 40: return ; 41: } 42: 43: int val = value; 44: 45: ALOGI("Set value %d to device led demo.", val); 46: 47: device->set_on(device, value); 48: } 49: 50: 51: static inline int led_demo_device_open(const hw_module_t *module, struct led_demo_device_t **device) 52: { 53: return module->methods->open(module, LED_DEMO_HARDWARE_DEVICE_ID, (struct hw_device_t **)device); 54: } 55: 56: 57: 58: static jint led_demo_init(JNIEnv *env, jclass clazz) 59: { 60: struct led_demo_module_t *module; 61: struct led_demo_device_t *device; 62: 63: 64: ALOGI("Initializing HAL stub led ......"); 65: 66: if(hw_get_module( LED_DEMO_HARDWARE_MODULE_ID , (const struct hw_module_t **)&module) == 0) 67: { 68: ALOGE("Device led demo found."); 69: 70: if(led_demo_device_open(&(module->common), &device)) 71: { 72: ALOGI("Device led demo is open."); 73: return (jint)device; 74: } 75: 76: ALOGE("Failed to open device led."); 77: 78: return 0; 79: } 80: 81: ALOGE("Failed to get HAL stub led demo."); 82: return 0; 83: } 84: 85: static const JNINativeMethod method_table[] = 86: { 87: {"init_native", "()I", (void *)led_demo_init}, 88: {"set_OFF_native", "(II)V", (void *)led_demo_setOFF}, 89: {"set_ON_native", "(II)V", (void *)led_demo_setON}, 90: }; 91: 92: int register_android_server_led_demo_service(JNIEnv *env) 93: { 94: return jniRegisterNativeMethods(env, "com/android/server/Led_demo_Service", 95: method_table, NELEM(method_table)); 96: } 97: 98: }; 99: 100:
修改frameworks/base/services/jni/onload.cpp文件:
1: namespace android { 2: ...... 3: int register_android_server_led_demo_service(JNIEnv *env); 4: }; 5: 6: extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) 7: { 8: ...... 9: register_android_server_led_demo_service(env); 10: 11: return JNI_VERSION_1_4; 12: }
修改frameworks/base/services/jni/Android.mk文件,内容如下:
1: LOCAL_SRC_FILES:= \ 2: ...... 3: com_android_server_led_demo_service.cpp \ 4: onload.cpp
最后,在Android源码顶层目录下执行:
mmm ./frameworks/base/services/jni/
- 启动硬件服务
-
修改frameworks/base/services/java/com/android/server/SystemServer.java文件
1: // Bring up services needed for UI. 2: if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { 3: ...... 4: try{ 5: Slog.i(TAG, "Led demo Service"); 6: ServiceManager.addService("led_demo", new Led_demo_Service()); //这里的名字要跟App中getService时传入的参数相同 7: } catch (Throwable e) { 8: Slog.e(TAG, "Failed to start Led demo Service", e); 9: } 10: 11: }
-
编写完成后,在Android源码顶层目录下执行:
mmm ./frameworks/base/services/java/
回到顶部(go to top)
六、编写App
这个app是在Win7下用eclipse开发的,如下图:
上面的错误是因为Win7下的SDK开发包中并没有我们编写的ILed_demo_service,这个不要紧。导出方法:在工程Tiny4412_led_demo上右键单击,点击Export,选择General----> File System ,选择导出路径,最后点击Finish。将导出的工程Tiny4412_led_demo拷贝到packages/experimental/目录下,然后进入packages/experimental/Tiny4412_led_demo,在其中创建一个Android.mk文件:
1: LOCAL_PATH:= $(call my-dir) 2: include $(CLEAR_VARS) 3: 4: LOCAL_MODULE_TAGS := optional 5: 6: # Only compile source java files in this apk. 7: LOCAL_SRC_FILES := $(call all-java-files-under, src) 8: 9: LOCAL_PACKAGE_NAME := Led_demo 10: 11: include $(BUILD_PACKAGE)
下面是最终的效果图:
完成操作后,在Android源码顶层目录下执行
mmm ./packages/experimental/Tiny4412_led_demo/
然后再执行
./gen-img.sh
将生成的system.img利用MiniTools提供的烧写工具烧写到板子上。
最后,附上源代码:
基于TINY4412的Andorid开发-------简单的LED灯控制.rar_免费高速下载|百度网盘-分享无限制
完!!
-