首页 / 操作系统 / Linux / 在Android中加入充电指示
基于Andriod系统的平台在没有硬件充电指示的情况下只有进入andriod系统才能进行充电指示,而我们有时候仅仅需要充电而不需要进入系统,本文介绍了实现这种功能的方法。具体过程如下:当内核启动后调用充电指示控制程序。充电指示程序发现如果外部供电就开始显示充电的画面,同时将设备的电源控制锁定为关闭状态(这样当拔掉电源时候系统自动关闭),如果在充电指示过程中又按了开机键,就重新开启电源按键。这个过程在单片机等简单系统上不值得一提,因为每个人都会想的比我好,这里重点介绍如何融合到andriod系统以及其中的我认为可以让别人参考的方法。方法一 ui显示部分。显然我们不能让系统跑的太深,否则控制起来就过于麻烦,充电显示等老半天才启动别人也觉得奇怪。所以有必要仅仅使用微型系统,微型系统自然能用的功能就少,在图像显示上面只能使用c语言操作framebuff,我的方法是参考bootable/recovery/minui/里面的库,其支持png的图片也文本显示,对于充电指示足够用了。一个可能遇到的问题是andriod提供的minui显示使用驱动的双buffer机制,在有的系统上不具备该功能,你可以强制只使用一个,修改graphics.c的函数gr_flip,将gr_active_fb 赋值为0。方法二 电池检测。 可以参考com_andriod_server_batteryService.cpp文件,基本上把里面的函数复制过来就可以使用。完成的charge充电程序必须加入到init.rc中才能被调用,我把它当做一个只运行一次的服务运行。service console /system/bin/busybox sh console#shuaiwen added,init.c has been hacked to block to wait this process to finishservice charge /system/bin/charge oneshot在init启动服务的过程都是非阻塞型的(新开一个线程运行),这会导致虽然服务已经被加入,但是系统还会完整启动,显然不能满足要求,实际的需求为当charge运行起来不应该运行其他服务。要实现这个目的,必须对init.c进行一点修改。我的方法是让init对启动的服务名称做判断,如果为charge就等待到该程序结束才继续运行。具体修改为改动init.c的函数service_start:if (pid == 0) {……..}//shuaiwen added begin else{ int status; if(strcmp(svc->name,"charge")==0) { wait(&status); //wait child to exist load_565rle_image(INIT_IMAGE_FILE);//redraw background } // else printf("shuaiwen skip process %s.",svc->name); } //shuaiwen added endif (pid < 0) {….}这样系统就会被charge阻塞住。Init.rc中排在charge后面的服务就暂时不会被启动。我上面改动的init.rc把charge服务放在console服务后面是因为我还是需要控制台调试。经过这样的改动,基本的充电服务就可以实现。我这里仅仅是举了一个例子,文中的例子仅仅供参考,请酌情参考。我写的一个简单的充电指示文件内容列在下面供大家参考。/*Copyright:GNUcharge monitor.revision history:2010/5/10 create shuaiwenicon path:/res/images/%s.png*/#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h> #include <linux/input.h>#include <pthread.h>#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/reboot.h>#include <sys/time.h>#include <time.h>#include <unistd.h> #include "minui/minui.h"#include "minzip/Zip.h"#define KEY_PWR 116 #define AC_ONLINE_PATH "/sys/class/power_supply/ac/online"#define USB_ONLINE_PATH "/sys/class/power_supply/usb/online"#define BATTERY_STATUS_PATH "/sys/class/power_supply/battery/status"#define BATTERY_HEALTH_PATH "/sys/class/power_supply/battery/health"#define BATTERY_PRESENT_PATH "/sys/class/power_supply/battery/present"#define BATTERY_CAPACITY_PATH "/sys/class/power_supply/battery/capacity"#define BATTERY_VOLTAGE_PATH "/sys/class/power_supply/battery/batt_vol"#define BATTERY_TEMPERATURE_PATH "/sys/class/power_supply/battery/batt_temp"#define BATTERY_TECHNOLOGY_PATH "/sys/class/power_supply/battery/technology" enum {BACKGROUND_ICON_CHARGE0,BACKGROUND_ICON_CHARGE1,BACKGROUND_ICON_CHARGE2,BACKGROUND_ICON_CHARGE3,BACKGROUND_ICON_CHARGE4,BACKGROUND_ICON_CHARGE5,BACKGROUND_ICON_END,}; enum {STATUSCHARGING,STATUSDISCHARGING,STATUSFULL,STATUSNOTCHARGING,STATUSUNKNOWN}; enum{HEALTHDEAD,HEALTHGOOD,HEALTHOVERHEAT,HEALTHOVERVOLTAGE,HEALTHUNKNOWN,HEALTHUNSPECIFIEDFAILURE,}; static gr_surface gBackgroundIcon[BACKGROUND_ICON_END];static const struct { gr_surface* surface; const char *name; } BITMAPS[] = { { &gBackgroundIcon[BACKGROUND_ICON_CHARGE0], "battery001" }, { &gBackgroundIcon[BACKGROUND_ICON_CHARGE1], "battery002" }, { &gBackgroundIcon[BACKGROUND_ICON_CHARGE2], "battery003" }, { &gBackgroundIcon[BACKGROUND_ICON_CHARGE3], "battery004" }, { &gBackgroundIcon[BACKGROUND_ICON_CHARGE4], "battery005" }, { &gBackgroundIcon[BACKGROUND_ICON_CHARGE5], "battery006" }, { NULL, NULL },}; static int readFromFile(const char* path, char* buf, size_t size){ int fd = open(path, O_RDONLY, 0); if (fd == -1) { //LOGE("Could not open "%s"", path); return -1; } size_t count = read(fd, buf, size); if (count > 0) { count = (count < size) ? count : size - 1; while (count > 0 && buf[count-1] == "
") count--; buf[count] = " "; } else { buf[0] = " "; } close(fd); return count;} static int getBatteryStatus(const char* status){ switch (status[0]) { case "C": return STATUSCHARGING; // Charging case "D": return STATUSDISCHARGING; // Discharging case "F": return STATUSFULL; // Not charging case "N": return STATUSNOTCHARGING; // Full case "U": return STATUSUNKNOWN; // Unknown default: { printf("Unknown battery status "%s"", status); return STATUSUNKNOWN; } }} static int getBatteryHealth(const char* status){ switch (status[0]) { case "D": return HEALTHDEAD; // Dead case "G": return HEALTHGOOD; // Good case "O": { if (strcmp(status, "Overheat") == 0) { return HEALTHOVERHEAT; } else if (strcmp(status, "Over voltage") == 0) { return HEALTHOVERVOLTAGE; } printf("Unknown battery health[1] "%s"", status); return HEALTHUNKNOWN; } case "U": { if (strcmp(status, "Unspecified failure") == 0) { return HEALTHUNSPECIFIEDFAILURE; } else if (strcmp(status, "Unknown") == 0) { return HEALTHUNKNOWN; } // fall through } default: { printf("Unknown battery health[2] "%s"", status); return HEALTHUNKNOWN; } }} static void ui_set_background(int icon){ gr_surface gIcon; gIcon=gBackgroundIcon[icon]; gr_color(0, 0, 0, 255); gr_fill(0, 0, gr_fb_width(), gr_fb_height()); if (gIcon) { //printf("set backgroupd:%s
",gBackgroundIcon[icon].name); int iconWidth = gr_get_width(gIcon); int iconHeight = gr_get_height(gIcon); int iconX = (gr_fb_width() - iconWidth) / 2; int iconY = (gr_fb_height() - iconHeight) / 2; gr_blit(gIcon, 0, 0, iconWidth, iconHeight, iconX, iconY); } gr_flip();} static void ui_init(){ gr_init(); ev_init(); int i; for (i = 0; BITMAPS[i].name != NULL; ++i) { int result = res_create_surface(BITMAPS[i].name, BITMAPS[i].surface); if (result < 0) { printf("Missing bitmap %s
(Code %d)
", BITMAPS[i].name, result); *BITMAPS[i].surface = NULL; } //else printf("create:%s
",BITMAPS[i].name); } }const int SIZE = 128; int power_ac(){ char buf[SIZE]; if (readFromFile(AC_ONLINE_PATH, buf, SIZE) > 0) { if (buf[0] == "1") { return 1; } }return 0; } /*function to indicate if the battery is present.*/int battery_present(){char buf[SIZE]; if (readFromFile(BATTERY_PRESENT_PATH, buf, SIZE) > 0) { if (buf[0] == "1") { return 1; } }return 0; } int battery_capacity(){char buf[SIZE]; if (readFromFile(BATTERY_CAPACITY_PATH, buf, SIZE) > 0) { return atoi(buf); } return 0;} int battery_voltage(){char buf[SIZE]; if (readFromFile(BATTERY_VOLTAGE_PATH, buf, SIZE) > 0) { return atoi(buf); } return 0;} int battery_temperature(){char buf[SIZE]; if (readFromFile(BATTERY_TEMPERATURE_PATH, buf, SIZE) > 0) { return atoi(buf); } return 0;} int capacity_full(){ char buf[SIZE]; if (readFromFile(BATTERY_STATUS_PATH, buf, SIZE) > 0) { return getBatteryStatus(buf); } } void do_nothing() //don"t commnet it before fix zip error. shuaiwen{ ZipArchive zip; mzOpenZipArchive(NULL, &zip); }int main(int argc, char **argv){ int index=0;#define CIRCLE 100 //1000x1000 microsecond int circle=0;//interval to update battery status.struct input_event ev; //is AC power charging?if(!power_ac()){printf("battery supply,don"t enter charge mode.
");return 0; //continue runing.}printf("entern charge mode
");//powerio_low(); //fixme,set power io low to shutdown system when unplug the power. ui_init(); while(1) { circle=0; ui_set_background(capacity_full()==STATUSCHARGING?index++%BACKGROUND_ICON_END:BACKGROUND_ICON_END-1);//todo:more condition must be considered. // ui_set_background(index++%BACKGROUND_ICON_END); while(circle++<CIRCLE) { usleep(1000); ev_get(&ev, 10); if((ev.type == EV_KEY)&&(ev.code==62)) { // powerio_high(); //fixme ev_exit(); gr_exit(); return 0;//the system will continue running } //debug if(ev.type==EV_KEY)printf("key:%d pressed
",ev.code); // } }ev_exit();gr_exit();return 0;} 对应的andriod.mk文件如下:LOCAL_PATH :=$(call my-dir) include $(CLEAR_VARS) charge_local_path := $(LOCAL_PATH)LOCAL_SRC_FILES :=main.cLOCAL_MODULE := chargeLOCAL_FORCE_STATIC_EXECUTABLE := true# This binary is in the recovery ramdisk, which is otherwise a copy of root.# It gets copied there in config/Makefile. LOCAL_MODULE_TAGS suppresses# a (redundant) copy of the binary in /system/bin for user builds.# TODO: Build the ramdisk image in a more principled way. LOCAL_MODULE_TAGS := eng LOCAL_STATIC_LIBRARIES := libminzip libunz libminui libpixelflinger_static libpng libcutils libstdc++ libc include $(BUILD_EXECUTABLE) include $(charge_local_path)/minui/Android.mkinclude $(charge_local_path)/minzip/Android.mk PRODUCT_COPY_FILES += $(charge_local_path)/res/images/battery001.PNG:system/res/images/battery001.png $(charge_local_path)/res/images/battery002.PNG:system/res/images/battery002.png $(charge_local_path)/res/images/battery003.PNG:system/res/images/battery003.png $(charge_local_path)/res/images/battery004.PNG:system/res/images/battery004.png $(charge_local_path)/res/images/battery005.PNG:system/res/images/battery005.png $(charge_local_path)/res/images/battery006.PNG:system/res/images/battery006.png