android button light 流程分析(二) — HAL & JNI

buttonandroidkeyboard代码分析jniresources

一、基础数据信息

首先看一下HAL定义的light类型:

  1. /** 
  2.  * The id of this module 
  3.  */  
  4. #define LIGHTS_HARDWARE_MODULE_ID "lights"  
  5.   
  6. /* 
  7.  * These light IDs correspond to logical lights, not physical. 
  8.  * So for example, if your INDICATOR light is in line with your 
  9.  * BUTTONS, it might make sense to also light the INDICATOR 
  10.  * light to a reasonable color when the BUTTONS are lit. 
  11.  */  
  12. #define LIGHT_ID_BACKLIGHT          "backlight"  
  13. #define LIGHT_ID_KEYBOARD           "keyboard"  
  14. #define LIGHT_ID_BUTTONS            "buttons"  
  15. #define LIGHT_ID_BATTERY            "battery"  
  16. #define LIGHT_ID_NOTIFICATIONS      "notifications"  
  17. #define LIGHT_ID_ATTENTION          "attention"  
  18.   
  19. /* 
  20.  * These lights aren't currently supported by the higher 
  21.  * layers, but could be someday, so we have the constants 
  22.  * here now. 
  23.  */  
  24. #define LIGHT_ID_BLUETOOTH          "bluetooth"  
  25. #define LIGHT_ID_WIFI               "wifi"  
可以看到我们常用的backlight,以及我们主要分析的buttons,当然还有呼吸灯的定义。然后看下定义的一些状态:
  1. #define LIGHT_FLASH_NONE            0  
  2.   
  3. /** 
  4.  * To flash the light at a given rate, set flashMode to LIGHT_FLASH_TIMED, 
  5.  * and then flashOnMS should be set to the number of milliseconds to turn 
  6.  * the light on, followed by the number of milliseconds to turn the light 
  7.  * off. 
  8.  */  
  9. #define LIGHT_FLASH_TIMED           1  
  10.   
  11. /** 
  12.  * To flash the light using hardware assist, set flashMode to 
  13.  * the hardware mode. 
  14.  */  
  15. #define LIGHT_FLASH_HARDWARE        2  
  16.   
  17. /** 
  18.  * Light brightness is managed by a user setting. 
  19.  */  
  20. #define BRIGHTNESS_MODE_USER        0  
  21.   
  22. /** 
  23.  * Light brightness is managed by a light sensor. 
  24.  */  
  25. #define BRIGHTNESS_MODE_SENSOR      1  
  26.   
  27. /** 
  28.  * The parameters that can be set for a given light. 
  29.  * 
  30.  * Not all lights must support all parameters.  If you 
  31.  * can do something backward-compatible, you should. 
  32.  */  
  33. struct light_state_t {  
  34.     /** 
  35.      * The color of the LED in ARGB. 
  36.      * 
  37.      * Do your best here. 
  38.      *   - If your light can only do red or green, if they ask for blue, 
  39.      *     you should do green. 
  40.      *   - If you can only do a brightness ramp, then use this formula: 
  41.      *      unsigned char brightness = ((77*((color>>16)&0x00ff)) 
  42.      *              + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8; 
  43.      *   - If you can only do on or off, 0 is off, anything else is on. 
  44.      * 
  45.      * The high byte should be ignored.  Callers will set it to 0xff (which 
  46.      * would correspond to 255 alpha). 
  47.      */  
  48.     unsigned int color;  
  49.   
  50.     /** 
  51.      * See the LIGHT_FLASH_* constants 
  52.      */  
  53.     int flashMode;  
  54.     int flashOnMS;  
  55.     int flashOffMS;  
  56.   
  57.     /** 
  58.      * Policy used by the framework to manage the light's brightness. 
  59.      * Currently the values are BRIGHTNESS_MODE_USER and BRIGHTNESS_MODE_SENSOR. 
  60.      */  
  61.     int brightnessMode;  
  62. };  
可以看到在flashMode为LIGHT_FLASH_TIMED时是呼吸灯的工作机制,flashOnMS定义了led从亮度0% - 100%经过的时间,flashOffMS定义了led从亮度100% - 0%经过的时间,需要驱动去实现渐变,如果不能渐变就只能是亮或灭两个状态。color值定义了不同情况下的亮度,可以按照说明进行转换。brightnessMode则定义了lcd背光的调整模式。接下来定义了light的设备模型:
  1. struct light_device_t {  
  2.     struct hw_device_t common;  
  3.   
  4.     /** 
  5.      * Set the provided lights to the provided values. 
  6.      * 
  7.      * Returns: 0 on succes, error code on failure. 
  8.      */  
  9.     int (*set_light)(struct light_device_t* dev,  
  10.             struct light_state_t const* state);  
  11. };  
其中set_light为设置各个light的接口,设备模型需要继承于HAL层统一的结构hw_device_t:
  1. /** 
  2.  * Every device data structure must begin with hw_device_t 
  3.  * followed by module specific public methods and attributes. 
  4.  */  
  5. typedef struct hw_device_t {  
  6.     /** tag must be initialized to HARDWARE_DEVICE_TAG */  
  7.     uint32_t tag;  
  8.   
  9.     /** version number for hw_device_t */  
  10.     uint32_t version;  
  11.   
  12.     /** reference to the module this device belongs to */  
  13.     struct hw_module_t* module;  
  14.   
  15.     /** padding reserved for future use */  
  16.     uint32_t reserved[12];  
  17.   
  18.     /** Close this device */  
  19.     int (*close)(struct hw_device_t* device);  
  20.   
  21. } hw_device_t;  
其中定义了一些公共接口和属性。其中hw_module_t定义了一些特殊信息:
  1. /** 
  2.  * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM 
  3.  * and the fields of this data structure must begin with hw_module_t 
  4.  * followed by module specific information. 
  5.  */  
  6. typedef struct hw_module_t {  
  7.     /** tag must be initialized to HARDWARE_MODULE_TAG */  
  8.     uint32_t tag;  
  9.   
  10.     /** major version number for the module */  
  11.     uint16_t version_major;  
  12.   
  13.     /** minor version number of the module */  
  14.     uint16_t version_minor;  
  15.   
  16.     /** Identifier of module */  
  17.     const char *id;  
  18.   
  19.     /** Name of this module */  
  20.     const char *name;  
  21.   
  22.     /** Author/owner/implementor of the module */  
  23.     const char *author;  
  24.   
  25.     /** Modules methods */  
  26.     struct hw_module_methods_t* methods;  
  27.   
  28.     /** module's dso */  
  29.     void* dso;  
  30.   
  31.     /** padding to 128 bytes, reserved for future use */  
  32.     uint32_t reserved[32-7];  
  33.   
  34. } hw_module_t;  
  35.   
  36. typedef struct hw_module_methods_t {  
  37.     /** Open a specific device */  
  38.     int (*open)(const struct hw_module_t* module, const char* id,  
  39.             struct hw_device_t** device);  
  40.   
  41. } hw_module_methods_t;  
二、代码流程分析

在HAL层一般采用固定格式定义一个新模块:

  1. /** Open a new instance of a lights device using name */  
  2. static int open_lights(const struct hw_module_t* module, char const* name,  
  3.         struct hw_device_t** device)  
  4. {  
  5.     int (*set_light)(struct light_device_t* dev,  
  6.             struct light_state_t const* state);  
  7.   
  8.     if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) {  // 根据名称设置相应的接口  
  9.         set_light = set_light_backlight;  
  10.     }  
  11.     else if (0 == strcmp(LIGHT_ID_BUTTONS, name)) {  
  12.         set_light = set_light_buttons;  
  13.     }  
  14.     else if (0 == strcmp(LIGHT_ID_BATTERY, name)) {  
  15.         set_light = set_light_battery;  
  16.     }  
  17.     else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) {  
  18.         set_light = set_light_notifications;  
  19.     }  
  20.     else if (0 == strcmp(LIGHT_ID_ATTENTION, name)) {  
  21.         set_light = set_light_attention;  
  22.     }  
  23.     else {  
  24.         LOGE("name %s\n", name);  
  25.         return -EINVAL;  
  26.     }  
  27.   
  28.     pthread_once(&g_init, init_globals);  
  29.     // 创建light_device_t  
  30.     struct light_device_t *dev = malloc(sizeof(struct light_device_t));  
  31.     memset(dev, 0, sizeof(*dev));  
  32.   
  33.     dev->common.tag = HARDWARE_DEVICE_TAG;  
  34.     dev->common.version = 0;  
  35.     dev->common.module = (struct hw_module_t*)module;  
  36.     // 关闭接口  
  37.     dev->common.close = (int (*)(struct hw_device_t*))close_lights;  
  38.     dev->set_light = set_light;  
  39.   
  40.     *device = (struct hw_device_t*)dev;  
  41.     return 0;  
  42. }  
  43.   
  44.   
  45. static struct hw_module_methods_t lights_module_methods = {  
  46.     .open =  open_lights,  
  47. };  
  48.   
  49. /* 
  50.  * The lights Module 
  51.  */  
  52. const struct hw_module_t HAL_MODULE_INFO_SYM = {  
  53.     .tag = HARDWARE_MODULE_TAG,       // 规定的tag  
  54.     .version_major = 1,  
  55.     .version_minor = 0,  
  56.     .id = LIGHTS_HARDWARE_MODULE_ID,  // 模块id  
  57.     .name = "atxx lights Module",     // 名称  
  58.     .author = "xxx",  
  59.     .methods = &lights_module_methods,// 方法  
  60. };  
JNI则调用如下方法获得操作接口:
  1. enum {  
  2.     LIGHT_INDEX_BACKLIGHT = 0,  
  3.     LIGHT_INDEX_KEYBOARD = 1,  
  4.     LIGHT_INDEX_BUTTONS = 2,  
  5.     LIGHT_INDEX_BATTERY = 3,  
  6.     LIGHT_INDEX_NOTIFICATIONS = 4,  
  7.     LIGHT_INDEX_ATTENTION = 5,  
  8.     LIGHT_INDEX_BLUETOOTH = 6,  
  9.     LIGHT_INDEX_WIFI = 7,  
  10.     LIGHT_COUNT  
  11. };  
  12.   
  13. struct Devices {  
  14.     light_device_t* lights[LIGHT_COUNT];  
  15. };  
  16.   
  17. static light_device_t* get_device(hw_module_t* module, char const* name)  
  18. {  
  19.     int err;  
  20.     hw_device_t* device;  
  21.     err = module->methods->open(module, name, &device);  
  22.     if (err == 0) {  
  23.         return (light_device_t*)device;  
  24.     } else {  
  25.         return NULL;  
  26.     }  
  27. }  
  28.   
  29. static jint init_native(JNIEnv *env, jobject clazz)  
  30. {  
  31.     int err;  
  32.     hw_module_t* module;  
  33.     Devices* devices;  
  34.       
  35.     devices = (Devices*)malloc(sizeof(Devices));  
  36.   
  37.     err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);  
  38.     if (err == 0) {  
  39.         devices->lights[LIGHT_INDEX_BACKLIGHT]  
  40.                 = get_device(module, LIGHT_ID_BACKLIGHT);  
  41.         devices->lights[LIGHT_INDEX_KEYBOARD]  
  42.                 = get_device(module, LIGHT_ID_KEYBOARD);  
  43.         devices->lights[LIGHT_INDEX_BUTTONS]  
  44.                 = get_device(module, LIGHT_ID_BUTTONS);  
  45.         devices->lights[LIGHT_INDEX_BATTERY]  
  46.                 = get_device(module, LIGHT_ID_BATTERY);  
  47.         devices->lights[LIGHT_INDEX_NOTIFICATIONS]  
  48.                 = get_device(module, LIGHT_ID_NOTIFICATIONS);  
  49.         devices->lights[LIGHT_INDEX_ATTENTION]  
  50.                 = get_device(module, LIGHT_ID_ATTENTION);  
  51.         devices->lights[LIGHT_INDEX_BLUETOOTH]  
  52.                 = get_device(module, LIGHT_ID_BLUETOOTH);  
  53.         devices->lights[LIGHT_INDEX_WIFI]  
  54.                 = get_device(module, LIGHT_ID_WIFI);  
  55.     } else {  
  56.         memset(devices, 0, sizeof(Devices));  
  57.     }  
  58.   
  59.     return (jint)devices;  
  60. }  
  61.   
  62. static void finalize_native(JNIEnv *env, jobject clazz, int ptr)  
  63. {  
  64.     Devices* devices = (Devices*)ptr;  
  65.     if (devices == NULL) {  
  66.         return;  
  67.     }  
  68.   
  69.     free(devices);  
  70. }  
  71.   
  72. static void setLight_native(JNIEnv *env, jobject clazz, int ptr,  
  73.         int light, int colorARGB, int flashMode, int onMS, int offMS, int brightnessMode)  
  74. {  
  75.     Devices* devices = (Devices*)ptr;  
  76.     light_state_t state;  
  77.   
  78.     if (light < 0 || light >= LIGHT_COUNT || devices->lights[light] == NULL) {  
  79.         return ;  
  80.     }  
  81.   
  82.     memset(&state, 0, sizeof(light_state_t));  
  83.     state.color = colorARGB;  
  84.     state.flashMode = flashMode;  
  85.     state.flashOnMS = onMS;  
  86.     state.flashOffMS = offMS;  
  87.     state.brightnessMode = brightnessMode;  
  88.   
  89.     devices->lights[light]->set_light(devices->lights[light], &state);  
  90. }  
  91.   
  92. static JNINativeMethod method_table[] = {  
  93.     { "init_native""()I", (void*)init_native },  
  94.     { "finalize_native""(I)V", (void*)finalize_native },  
  95.     { "setLight_native""(IIIIIII)V", (void*)setLight_native },  
  96. };  
  97.   
  98. int register_android_server_LightsService(JNIEnv *env)  
  99. {  
  100.     return jniRegisterNativeMethods(env, "com/android/server/LightsService",  
  101.             method_table, NELEM(method_table));  
  102. }  
HAL层实现具体操作的代码如下:
  1. static pthread_once_t g_init = PTHREAD_ONCE_INIT;  
  2. static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;  
  3. // 操作led的名称以及句柄  
  4. struct led_prop {  
  5.     const char *filename;  
  6.     int fd;  
  7. };  
  8. // 3个操作的集合  
  9. struct led {  
  10.     struct led_prop brightness;  
  11.     struct led_prop flash_on_ms;  
  12.     struct led_prop flash_off_ms;  
  13. };  
  14. // 系统拥有的light  
  15. enum {  
  16.     RED_LED,  
  17.     GREEN_LED,  
  18.     BLUE_LED,  
  19.     LCD_BACKLIGHT,  
  20.     BUTTONS_LED,  
  21.     NUM_LEDS,  
  22. };  
  23. // 操作各light的节点  
  24. struct led leds[NUM_LEDS] = {  
  25.     [RED_LED] = {  
  26.         .brightness = { "/sys/class/leds/red/brightness", -1},  
  27.         .flash_on_ms = { "/sys/class/leds/red/delay_on", -1},  
  28.         .flash_off_ms = { "/sys/class/leds/red/delay_off", -1},  
  29.     },  
  30.     [GREEN_LED] = {  
  31.         .brightness = { "/sys/class/leds/green/brightness", -1},  
  32.         .flash_on_ms = { "/sys/class/leds/green/delay_on", -1},  
  33.         .flash_off_ms = { "/sys/class/leds/green/delay_off", -1},  
  34.     },  
  35.     [BLUE_LED] = {  
  36.         .brightness = { "/sys/class/leds/blue/brightness", -1},  
  37.         .flash_on_ms = { "/sys/class/leds/blue/delay_on", -1},  
  38.         .flash_off_ms = { "/sys/class/leds/blue/delay_off", -1},  
  39.     },  
  40.     [LCD_BACKLIGHT] = {  
  41.         .brightness = { "/sys/class/backlight/backlight/brightness", -1},  
  42.     },  
  43.     [BUTTONS_LED] = {  
  44.         .brightness = {"/sys/class/leds/button-backlight/brightness", -1},  
  45.     },  
  46. };  
  47.   
  48. static int is_battery_light_on = 0;  
  49. /** 
  50.  * device methods 
  51.  */  
  52. // 初始化单个节点  
  53. static int init_prop(struct led_prop *prop)  
  54. {  
  55.     int fd;  
  56.   
  57.     prop->fd = -1;  
  58.     if (!prop->filename)  
  59.         return 0;  
  60.     fd = open(prop->filename, O_RDWR);  
  61.     if (fd < 0) {  
  62.         LOGE("init_prop: %s cannot be opened (%s)\n", prop->filename,  
  63.              strerror(errno));  
  64.         return -errno;  
  65.     }  
  66.   
  67.     prop->fd = fd;  
  68.     return 0;  
  69. }  
  70. // 关闭节点  
  71. static void close_prop(struct led_prop *prop)  
  72. {  
  73.     int fd;  
  74.   
  75.     if (prop->fd > 0)  
  76.         close(prop->fd);  
  77.     return;  
  78. }  
  79. // 初始化全部节点  
  80. void init_globals(void)  
  81. {  
  82.     int i;  
  83.     pthread_mutex_init(&g_lock, NULL);  
  84.   
  85.     for (i = 0; i < NUM_LEDS; ++i) {  
  86.         init_prop(&leds[i].brightness);  
  87.         init_prop(&leds[i].flash_on_ms);  
  88.         init_prop(&leds[i].flash_off_ms);  
  89.     }  
  90. }  
  91. // 向节点写数据控制light  
  92. static int write_int(struct led_prop *prop, int value)  
  93. {  
  94.     char buffer[20];  
  95.     int bytes;  
  96.     int amt;  
  97.   
  98.     if (prop->fd < 0)  
  99.         return 0;  
  100.   
  101.     LOGV("%s %s: 0x%x\n", __func__, prop->filename, value);  
  102.   
  103.     bytes = snprintf(buffer, sizeof(buffer), "%d\n", value);  
  104.     while (bytes > 0) {  
  105.         amt = write(prop->fd, buffer, bytes);  
  106.         if (amt < 0) {  
  107.             if (errno == EINTR)  
  108.                 continue;  
  109.             return -errno;  
  110.         }  
  111.         bytes -= amt;  
  112.     }  
  113.   
  114.     return 0;  
  115. }  
  116. // 用于呼吸灯控制  
  117. static int set_speaker_light(struct light_device_t* dev,  
  118.         struct light_state_t const* state)  
  119. {  
  120.     int len;  
  121.     int value;  
  122.     unsigned int colorRGB;  
  123.     unsigned int colorR;  
  124.     unsigned int colorG;  
  125.     unsigned int colorB;  
  126.   
  127.     colorRGB = state->color & 0xFFFFFF;  
  128.     if (colorRGB == 0xFFFFFF) { /* white */  
  129.         colorRGB = 0x0;  
  130.     }  
  131.     colorR = (colorRGB >> 16) & 0x00ff;  
  132.     colorG = (colorRGB >> 8) & 0x00ff;  
  133.     colorB = colorRGB & 0x00ff;  
  134.   
  135.     pthread_mutex_lock(&g_lock);  
  136.     switch (state->flashMode) {  
  137.         case LIGHT_FLASH_TIMED:  
  138.         case LIGHT_FLASH_HARDWARE:  
  139.             if (colorR) {  
  140.                 write_int(&leds[RED_LED].flash_on_ms, state->flashOnMS);  
  141.                 write_int(&leds[RED_LED].flash_off_ms, state->flashOffMS);  
  142.             } else {  /*off*/  
  143.                 write_int(&leds[RED_LED].flash_on_ms, 0);  
  144.             }  
  145.             if (colorG) {  
  146.                 write_int(&leds[GREEN_LED].flash_on_ms, state->flashOnMS);  
  147.                 write_int(&leds[GREEN_LED].flash_off_ms, state->flashOffMS);  
  148.             } else {  /*off*/  
  149.                 write_int(&leds[GREEN_LED].flash_on_ms, 0);  
  150.             }  
  151.             if (colorB) {  
  152.                 write_int(&leds[BLUE_LED].flash_on_ms, state->flashOnMS);  
  153.                 write_int(&leds[BLUE_LED].flash_off_ms, state->flashOffMS);  
  154.             } else {  /*off*/  
  155.                 write_int(&leds[BLUE_LED].flash_on_ms, 0);  
  156.             }  
  157.             break;  
  158.   
  159.         case LIGHT_FLASH_NONE:  
  160.             if (colorR) {  
  161.                 write_int(&leds[RED_LED].flash_on_ms, 255);  
  162.                 write_int(&leds[RED_LED].flash_off_ms, 0);  
  163.             } else {  /*off*/  
  164.                 write_int(&leds[RED_LED].flash_on_ms, 0);  
  165.             }  
  166.             if (colorG) {  
  167.                 write_int(&leds[GREEN_LED].flash_on_ms, 255);  
  168.                 write_int(&leds[GREEN_LED].flash_off_ms, 0);  
  169.             } else {  /*off*/  
  170.                 write_int(&leds[GREEN_LED].flash_on_ms, 0);  
  171.             }  
  172.             if (colorB) {  
  173.                 write_int(&leds[BLUE_LED].flash_on_ms, 255);  
  174.                 write_int(&leds[BLUE_LED].flash_off_ms, 0);  
  175.             } else {  /*off*/  
  176.                 write_int(&leds[BLUE_LED].flash_on_ms, 0);  
  177.             }  
  178.             break;  
  179.   
  180.         default:  
  181.             LOGE("set_led_state colorRGB=%08X, unknown mode %d\n",  
  182.                   colorRGB, state->flashMode);  
  183.     }  
  184.     pthread_mutex_unlock(&g_lock);  
  185.     return 0;  
  186. }  
  187. // rgb数据转换成背光值  
  188. static int rgb_to_brightness(struct light_state_t const* state)  
  189. {  
  190.     int color = state->color & 0x00ffffff;  
  191.     return ((77*((color>>16)&0x00ff))              
  192.             + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;  
  193. }  
  194. // 设置按键灯亮度  
  195. static int set_light_buttons(struct light_device_t* dev,  
  196.         struct light_state_t const* state)  
  197. {  
  198.     int err = 0;  
  199.     int brightness = rgb_to_brightness(state);  
  200.     LOGE("%s brightness=%d color=0x%08x",  
  201.             __func__, brightness, state->color);  
  202.     err = write_int(&leds[BUTTONS_LED].brightness, brightness);  
  203.     return err;  
  204. }  
  205. // 设置lcd背光亮度  
  206. static int set_light_backlight(struct light_device_t* dev,  
  207.         struct light_state_t const* state)  
  208. {  
  209.     int err = 0;  
  210.     int brightness = rgb_to_brightness(state);  
  211.     LOGV("%s brightness=%d color=0x%08x",  
  212.             __func__, brightness, state->color);  
  213.     err = write_int(&leds[LCD_BACKLIGHT].brightness, brightness);  
  214.     return err;  
  215. }  
  216. // 设置低电light  
  217. static int set_light_battery(struct light_device_t* dev,  
  218.         struct light_state_t const* state)  
  219. {  
  220.     int colorRGB = state->color & 0xFFFFFF;  
  221.     LOGD("%s flashMode %d, flashOnMs %d, flashOffMs %d, color=0x%08x\n",  
  222.             __func__, state->flashMode, state->flashOnMS, state->flashOffMS, state->color);  
  223.     if (colorRGB != 0x0 && colorRGB != 0xFFFFFF) {  
  224.         is_battery_light_on = 1;  
  225.     } else  {  
  226.         is_battery_light_on = 0;  
  227.     }  
  228.     return set_speaker_light(dev, state);  
  229. }  
  230. // 设置通知light  
  231. static int set_light_notifications(struct light_device_t* dev,  
  232.         struct light_state_t const* state)  
  233. {  
  234.     LOGD("%s flashMode %d, flashOnMs %d, flashOffMs %d, color=0x%08x\n",  
  235.             __func__, state->flashMode, state->flashOnMS, state->flashOffMS, state->color);  
  236.     if (!is_battery_light_on) {  
  237.         set_speaker_light(dev, state);  
  238.     }  
  239.     return 0;  
  240. }  
  241. // 设置提醒light  
  242. static int set_light_attention(struct light_device_t* dev,  
  243.         struct light_state_t const* state)  
  244. {  
  245.     LOGD("%s flashMode %d, flashOnMs %d, flashOffMs %d, color=0x%08x\n",  
  246.             __func__, state->flashMode, state->flashOnMS, state->flashOffMS, state->color);  
  247.     if (!is_battery_light_on) {  
  248.         set_speaker_light(dev, state);  
  249.     }  
  250.     return 0;  
  251. }  
  252.   
  253. // 关闭light  
  254. static int close_lights(struct light_device_t *dev)  
  255. {  
  256.     int i;  
  257.   
  258.     for (i = 0; i < NUM_LEDS; ++i) {  
  259.         close_prop(&leds[i].brightness);  
  260.         close_prop(&leds[i].flash_on_ms);  
  261.         close_prop(&leds[i].flash_off_ms);  
  262.     }  
  263.   
  264.     if (dev) {  
  265.         free(dev);  
  266.     }  
  267.     return 0;  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值