zoukankan      html  css  js  c++  java
  • Android灯光系统(2)——HAL实现

    1.Android系统中定义了如下一些灯

    /frameworks/android_hardware/libhardware/include/hardware/lights.h
    #define LIGHT_ID_BACKLIGHT          "backlight"
    #define LIGHT_ID_KEYBOARD           "keyboard"
    #define LIGHT_ID_BUTTONS            "buttons"
    #define LIGHT_ID_BATTERY            "battery"
    #define LIGHT_ID_NOTIFICATIONS      "notifications"
    #define LIGHT_ID_ATTENTION          "attention"
    还有两个未实现的:
    #define LIGHT_ID_BLUETOOTH          "bluetooth"
    #define LIGHT_ID_WIFI               "wifi"

    2.编写lights的hal文件

    好的参考例子,sony手机使用的,移植这个程序: https://android.googlesource.com/device/sony/lt26/+/master/liblight/lights.c
    移植后的hal文件如下:

    /*
    移植:
    https://android.googlesource.com/device/sony/lt26/+/master/liblight/lights.c
    
    */
    
    /*是在发布版软件中的ALOGV()能打印出来*/
    #define LOG_NDEBUG 0
    
    #define LOG_TAG "lights"
    #include <cutils/log.h>
    #include <stdint.h>
    #include <string.h>
    #include <unistd.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <pthread.h>
    #include <sys/ioctl.h>
    #include <sys/types.h>
    #include <hardware/lights.h>
    
    char const*const RED_LED_FILE                 = "/sys/class/leds/led1/brightness";
    char const*const GREEN_LED_FILE             = "/sys/class/leds/led2/brightness";
    char const*const BLUE_LED_FILE             = "/sys/class/leds/led3/brightness";
    
    char const*const RED_LED_FILE_TRIGGER        = "/sys/class/leds/led1/trigger";
    char const*const GREEN_LED_FILE_TRIGGER    = "/sys/class/leds/led2/trigger";
    char const*const BLUE_LED_FILE_TRIGGER    = "/sys/class/leds/led3/trigger";
    
    char const*const RED_LED_FILE_DELAYON        = "/sys/class/leds/led1/delay_on";
    char const*const GREEN_LED_FILE_DELAYON    = "/sys/class/leds/led2/delay_on";
    char const*const BLUE_LED_FILE_DELAYON    = "/sys/class/leds/led3/delay_on";
    
    char const*const RED_LED_FILE_DELAYOFF    = "/sys/class/leds/led1/delay_off";
    char const*const GREEN_LED_FILE_DELAYOFF = "/sys/class/leds/led2/delay_off";
    char const*const BLUE_LED_FILE_DELAYOFF    = "/sys/class/leds/led3/delay_off";
    
    char const*const LCD_BACKLIGHT_FILE       = "/dev/backlight-1wire";
    
    /* Synchronization primities */
    static pthread_once_t g_init = PTHREAD_ONCE_INIT;
    static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
    /* Mini-led state machine */
    static struct light_state_t g_notification;
    static struct light_state_t g_battery;
    
    
    static int write_int (const char *path, int value) {
        int fd;
        /*使用这个静态变量只提示一次*/
        static int already_warned = 0;
        fd = open(path, O_RDWR);
        if (fd < 0) {
            int errno_ret = errno;
            if (already_warned == 0) {
                ALOGE("write_int open %s failed,ret=%d
    ", path, fd);
                already_warned = 1;
            }
            return -errno_ret;
        }
        char buffer[20];
        
        /*sysfs文件写入的是字符串,因此还需要将数值转换为字符串后写入*/
        int bytes = snprintf(buffer, sizeof(buffer), "%d
    ", value);
        int written = write (fd, buffer, bytes);
        close(fd);
        return written == -1 ? -errno : 0;
    }
    
    static int write_string (const char *path, const char *value) {
        int fd;
        static int already_warned = 0;
        fd = open(path, O_RDWR);
        if (fd < 0) {
            int errno_ret = errno;
            if (already_warned == 0) {
                ALOGE("write_string failed to open %s
    ", path);
                already_warned = 1;
            }
            return -errno_ret;
        }
        char buffer[20];
        int bytes = snprintf(buffer, sizeof(buffer), "%s
    ", value);
        int written = write (fd, buffer, bytes);
        close(fd);
        return written == -1 ? -errno : 0;
    }
    
    /* Color tools */
    static int is_lit (struct light_state_t const* state) {
        return state->color & 0x00ffffff;
    }
    static int rgb_to_brightness (struct light_state_t const* state) {
        int color = state->color & 0x00ffffff;
        return ((77*((color>>16)&0x00ff))
                + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
    }
    
    /* The actual lights controlling section */
    static int set_light_backlight (struct light_device_t *dev, struct light_state_t const *state) {
        int brightness = rgb_to_brightness(state);
        ALOGV("%s brightness=%d color=0x%08x", __func__,brightness, state->color);
    
        /*加个锁表示希望是线程安全的*/
        pthread_mutex_lock(&g_lock);
        /* App传下来brightness 0-255,但是驱动只支持0-127,因此除以2 */
        write_int (LCD_BACKLIGHT_FILE, brightness/2);
        pthread_mutex_unlock(&g_lock);
        
        return 0;
    }
    
    /*这个实验中的三个灯模拟的是一个灯*/
    static void set_shared_light_locked (struct light_device_t *dev, struct light_state_t *state) {
        int r, g, b;
        int delayOn,delayOff;
        r = (state->color >> 16) & 0xFF;
        g = (state->color >> 8) & 0xFF;
        b = (state->color) & 0xFF;
        delayOn = state->flashOnMS;
        delayOff = state->flashOffMS;
        /*需要led闪烁,三个led全部闪烁*/
        if (state->flashMode != LIGHT_FLASH_NONE) {
            write_string (RED_LED_FILE_TRIGGER, "timer");
            write_string (GREEN_LED_FILE_TRIGGER, "timer");
            write_string (BLUE_LED_FILE_TRIGGER, "timer");
            write_int (RED_LED_FILE_DELAYON, delayOn);
            write_int (GREEN_LED_FILE_DELAYON, delayOn);
            write_int (BLUE_LED_FILE_DELAYON, delayOn);
            write_int (RED_LED_FILE_DELAYOFF, delayOff);
            write_int (GREEN_LED_FILE_DELAYOFF, delayOff);
            write_int (BLUE_LED_FILE_DELAYOFF, delayOff);
        } else {
            write_string (RED_LED_FILE_TRIGGER, "none");
            write_string (GREEN_LED_FILE_TRIGGER, "none");
            write_string (BLUE_LED_FILE_TRIGGER, "none");
        }
    
        /*虽然上面同时触发了闪烁,但是如果写的是0,会关闭对应的led*/
        write_int (RED_LED_FILE, r);
        write_int (GREEN_LED_FILE, g);
        write_int (BLUE_LED_FILE, b);
    }
    
    /*sony的通知灯和电池灯共用一个led,通知灯的优先级更高*/
    static void handle_shared_battery_locked (struct light_device_t *dev) {
        /*优先作为通知灯使用*/
        if (is_lit (&g_notification)) {
            set_shared_light_locked (dev, &g_notification);
        } else {
            set_shared_light_locked (dev, &g_battery);
        }
    }
    static int set_light_battery (struct light_device_t *dev, struct light_state_t const* state) {
    
        ALOGV("%s flashMode=%d onMS = %d offMS = %d color=0x%08x", __func__,state->flashMode,state->flashOnMS,state->flashOffMS,state->color);
    
        pthread_mutex_lock (&g_lock);
        g_battery = *state;
        handle_shared_battery_locked(dev);
        pthread_mutex_unlock (&g_lock);
        return 0;
    }
    static int set_light_notifications (struct light_device_t *dev, struct light_state_t const* state) {
        ALOGV("%s flashMode=%d onMS = %d offMS = %d color=0x%08x", __func__,state->flashMode,state->flashOnMS,state->flashOffMS,state->color);
        pthread_mutex_lock (&g_lock);
        g_notification = *state;
        handle_shared_battery_locked(dev);
        pthread_mutex_unlock (&g_lock);
        return 0;
    }
    /* Initializations */
    void init_globals () {
        pthread_mutex_init (&g_lock, NULL);
    }
    /* Glueing boilerplate */
    static int close_lights (struct light_device_t *dev) {
        if (dev)
            free(dev);
        return 0;
    }
    
    /*这个参数可能被传入多个name,获取多个name的led*/
    static int open_lights (const struct hw_module_t* module, char const* name,
                            struct hw_device_t** device) {
        int (*set_light)(struct light_device_t* dev,
                         struct light_state_t const *state);
    
        /*若获取的是"backlight"灯,就返回"backlight"灯的设置方法*/
        if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) {
            set_light = set_light_backlight;
        }/*若获取的是"battery"灯,就返回"battery"灯的设置方法*/
        else if (0 == strcmp(LIGHT_ID_BATTERY, name)) {
            set_light = set_light_battery;
        }/*若获取的是"notifications"灯,就返回"notifications"灯的设置方法*/
        else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) {
            set_light = set_light_notifications;
        }/*其它灯不支持*/
        else {
            /*没获取到帮JNI设置为NULL*/
            *device = NULL;
            return -EINVAL;
        }
    
        /*
         * 这句确保只执行一次,对于hal文件这个技术和有用,因为可能要支持多线程,而且只需要执行一次.
         * 此处使用静态变量效率应该还高一些。
         */
        pthread_once (&g_init, init_globals);
        
        struct light_device_t *dev = malloc(sizeof (struct light_device_t));
        memset(dev, 0, sizeof(*dev));
        dev->common.tag     = HARDWARE_DEVICE_TAG;
        dev->common.version = 0;
        dev->common.module     = (struct hw_module_t*)module;
        dev->common.close     = (int (*)(struct hw_device_t*))close_lights;
        dev->set_light     = set_light; /*这个是对应灯的设置方法*/
    
        /*这个结构体返回给JNI*/
        *device = (struct hw_device_t*)dev;
        
        return 0;
    }
    
    
    static struct hw_module_methods_t lights_module_methods = {
        .open = open_lights,
    };
    
    struct hw_module_t HAL_MODULE_INFO_SYM = {
        .tag = HARDWARE_MODULE_TAG,
        .version_major = 1,
        .version_minor = 0,
        .id = LIGHTS_HARDWARE_MODULE_ID, /*"lights"*/
        .name = "Transplant from Sony lights module",
        .author = "Freedom Mr.Sun",
        .methods = &lights_module_methods,
    };
    View Code

    然后放在hardware/libhardware/modules/lights/下,移植Android.mk进行编译。

    同时还要把系统原有的那个不开源的lights.tiny4412.so从系统中移除:
    vi vendor/friendly-arm/tiny4412/device-tiny4412.mk

    ifeq ($(BOARD_USES_PWMLIGHTS),false)
    # 注释掉这两行
    # PRODUCT_COPY_FILES += 
    #       $(VENDOR_PATH)/proprietary/lights.tiny4412.so:system/lib/hw/lights.tiny4412.so
    endif
    View Code

    3.编译遇到问题一:
    编译进system.img里面的lights.tiny4412.so还是这个不开源的,不是我们实现的,但是
    out/target/product/tiny4412/system/lib/hw/lights.tiny4412.so已经是我们实现的了。此时删除out/target/product/tiny4412/system.img
    和顶层目录下的system.img,然后重新make snod, ./gen-img.sh,然后生成的system.img里面就是使用我们自己实现的hal了。

    4.遇到问题二:
    hal文件中的ALOGV()的打印并没有打印出来,在/system/.../cutil/log.h中有说明在发布版软件中ALOGV()的打印是会被丢弃的,若不被想
    丢在源文件的最上面加:#define LOG_NDEBUG 0
    因此不重要的信息尽量使用ALOGV()来打印,这样软件在release版本中会自动去除。

    5.遇到问题三:
    /sys/class/leds/led1/trigger无法使用open(O_RDWR)打开,原因是权限不够,Android和Linux不同,Android是以普通用户登录的,属性
    文件制定644权限是不可写的,因此需要将trigger,brightness,delay_off,delay_on中需要写的设置为0666权限。

    6.mmm -B 强制编译,没有修改代码但是要重新编译的时候使用

    7.tiny4412上调节背光的操作:
    Setting --> Display --> Brightness Level -->可以手动调节背光的亮度

    8.LCD背光灯调节
    tiny4412操作LCD背光,这个4412厂家没有给出源码,只给出了一个.so的库,源文件在vendor/friendly-arm/tiny4412/proprietary/lights.tiny4412.so
    文件系统中在/system/lib/hw/lights.tiny4412.so。
    若是不知道这个库操作的是哪个设备文件,可以把这个库反汇编出来,然后看它操作了哪些设备文件。
    其实也不用反汇编,使用AltraEdit打开它然后查找,选择ASCII,搜索/dev,发现其打开的设备文件是/dev/backlight-1wire

    在tiny4412上果然有/dev/backlight-1wire,对应内核中文件为tiny4412_1wire_host.c,由其write()看出只需要向里面写个整数值就能调整
    背光,测试:
    shell@tiny4412:/system # echo 127 > /dev/backlight-1wire //背光开到最大
    shell@tiny4412:/system # echo 0 > /dev/backlight-1wire //关闭背光
    shell@tiny4412:/system # echo 10 > /dev/backlight-1wire //调节背光
    会自动把"127"转换为127

  • 相关阅读:
    Insus Meta Utility
    The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine.
    Insus Binary Utility
    asp.net实现文件下载功能
    Column 'Column Name' does not belong to table Table
    程序已被编译为DLL,怎样去修改程序功能
    如何在Web网站实现搜索功能
    如何把数据流转换为二进制字符串
    Asp.net更新文件夹的文件
    如何显示中文月份
  • 原文地址:https://www.cnblogs.com/hellokitty2/p/10812208.html
Copyright © 2011-2022 走看看