查看: 7811|回复: 3

[经验] 基于TINY4412的Andorid开发-------简单的LED灯控制

[复制链接]
  • TA的每日心情
    奋斗
    2016-8-15 09:28
  • 签到天数: 222 天

    连续签到: 1 天

    [LV.7]常住居民III

    发表于 2014-7-25 14:37:29 | 显示全部楼层 |阅读模式
    分享到:
    参考资料:
    《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
    下面开始:
    一、编写驱动程序
    分析tiny4412的原理图,看一下LED灯的位置:
    210858146972000.png
    可以知道,LED是低电平亮,高电平灭。
    看一下,接到了Exynos4412的哪些引脚上了:
    210858164162442.png
    可以看到:
    LED1  --------- GPM4_0
    LED2  --------- GPM4_1
    LED3  --------- GPM4_2
    LED4  --------- GPM4_3
    看一下Exynos4412的芯片手册,看一下GPM4的相关寄存器:
    210858184472854.png
    图中第二列表示的相对于基地址的偏移量,这里基地址是:0x11000000.
    在芯片手册的Page288 ~ Page291对这些寄存器有更详细的介绍。
    以GPM4_0引脚为例:
    210858197914111.png
    为了控制灯,[3:0]应设置为0x01,即输出模式
    210858212291638.png
    向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选择为*,然后保存配置退出。
    210858221042737.png

    注:执行上面这些操作之前,确保已经按照友善之臂的手册,成功编译了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用户手册》

    二、编写代码测试驱动程序
    在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登陆板子,进行测试。
    三、编写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:          idED_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将其烧写到板子上。
    四、编写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类。

    五、编写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/
    六、编写App
    这个app是在Win7下用eclipse开发的,如下图:
    210858239009921.png

    上面的错误是因为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)
    下面是最终的效果图:
    210858247607791.png

    完成操作后,在Android源码顶层目录下执行
    mmm ./packages/experimental/Tiny4412_led_demo/
    然后再执行
    ./gen-img.sh
    将生成的system.img利用MiniTools提供的烧写工具烧写到板子上。

    最后,附上源代码:

    http://pan.baidu.com/s/1ntwTz1B
    完!!
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2023-9-15 06:28
  • 签到天数: 3747 天

    连续签到: 60 天

    [LV.Master]伴坛终老

    发表于 2014-7-25 15:27:52 | 显示全部楼层
    好共享啊!慷慨!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2013-9-2 09:06
  • 签到天数: 11 天

    连续签到: 1 天

    [LV.3]偶尔看看II

    发表于 2014-7-25 16:07:03 | 显示全部楼层
    路过,赞一个
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2014-9-23 05:09
  • 签到天数: 113 天

    连续签到: 1 天

    [LV.6]常住居民II

    发表于 2014-7-25 17:02:10 | 显示全部楼层
    很详细,学习了,谢谢分享
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条



    手机版|小黑屋|与非网

    GMT+8, 2025-1-26 05:53 , Processed in 0.141991 second(s), 22 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.