电源管理之充电动画

一、充电动画的启动入口

    充电动画是通过通过启动 kpoc_charger.rc的方式启动

 kpoc_charger.rc的内容:

on charger
    start kpoc_charger  //充电打印服务

service kpoc_charger /system/bin/kpoc_charger
    class charger    //充电服务

 所以充电动画是在lk kernel都启动后才启动的服务。

二、charger 服务

     1.charger服务的启动入口是main.cpp,具体代码如下

int main(__attribute__((unused))int argc, __attribute__((unused))char *argv[])
{
   
	KPOC_LOGI("charging mainargc=%d,argv=%s\n",argc,argv);
    set_draw_anim_mode(1);
    pthread_mutex_init(&lights_mutex, NULL);

    setpriority(PRIO_PROCESS, 0, -20);
    FILE *oom_adj = fopen("/proc/self/oom_score_adj", "w");
    if (oom_adj) {
        fputs("-17", oom_adj);
        fclose(oom_adj);
    }

    //stop_backlight();
    KPOC_LOGI("stop_backlight 1\n");
//充电动画的初始化,1.打开fb :dev/graphics/fb0 framebuffer驱动 2.充电类型的选择 mtk里面有两个充电类型一个老的一个是新的,呈现的界面不同而且。
    bootlogo_init();

    alarm_control();
 //实现充电动画的逻辑,创建一个draw_with_interval线程来渲染画布,并通过dev/graphics/fb0 来更新显示画面  ioctl(fb_fd, FBIOPUT_VSCREENINFO, &vinfo)
    charging_control();

    unsigned int i;
    for (i=0; i< ARRAY_SIZE(pwrkeys); i++)
        KPOC_LOGI("pwrkeys[%d]:%d\n",i,pwrkeys[i]);

	//loop 监听按键开关,随时停止动画,启动设备
    key_control(pwrkeys, ARRAY_SIZE(pwrkeys)); //will loop inside

    return 0;
}

 2.

void bootlogo_init()
{
    KPOC_LOGI("[ChargingAnimation: %s %d]\n",__FUNCTION__,__LINE__);
    sync_anim_version();//设置动画走的是哪个版本 old version new version
    anim_init(); //初始化
}

3.charging_animation.cpp ->anim_init()

void anim_init()
{
   
    KPOC_LOGI("anim_init");
    if (MTK_LOG_ENABLE == 1) {
        KPOC_LOGI("[libshowlogo: %s %d]\n",__FUNCTION__,__LINE__);
    }
	//挂载文件系统,确定动画走的是哪个版本
    anim_logo_init();
   //根据前面设置的版本不同选择不同的分支
    if (draw_anim_mode == (DRAW_ANIM_MODE_FB)) {
        anim_fb_init();//初始化屏幕信息
    } else {
        anim_surface_init();//初始化屏幕信息
    }
}

4.

void anim_logo_init(void)
{


    // read and de-compress logo data here
    int fd = 0;
    int len = 0;
    struct fstab_rec* rec;

    fstab = fs_mgr_read_fstab_default();//文件挂载
    if (!fstab) {
        if (MTK_LOG_ENABLE == 1) {
            KPOC_LOGI("failed to open fstab\n");
        }
        error_flag = 1;
        return;
    }
//挂载logo.bin文件
    rec = fs_mgr_get_entry_for_mount_point(fstab, LOGO_MNT_POINT);
    if (rec == NULL) {
        if (MTK_LOG_ENABLE == 1) {
            KPOC_LOGI("failed to get entry for %s\n", LOGO_MNT_POINT);
        }
        error_flag = 1;
        return;
    }

    // "rec->blk_device" is the path 块设备
    fd = open(rec->blk_device, O_RDONLY);
    // get logo patition from fstab end
    if(fd < 0)
    {
        if (MTK_LOG_ENABLE == 1) {
            KPOC_LOGI("[libshowlogo: %s %d]open logo partition device file fail, errno = %d \n",__FUNCTION__,__LINE__ , errno);
        }
        goto error_return;
    }

    logo_addr = (unsigned int*)malloc(LOGO_BUFFER_SIZE);
    if(logo_addr == NULL)
    {
        if (MTK_LOG_ENABLE == 1) {
            KPOC_LOGI("[libshowlogo: %s %d]allocate logo buffer fail, size=0x%08x \n",__FUNCTION__,__LINE__ , LOGO_BUFFER_SIZE);
        }
        goto error_return;
    }

    // (1) skip the image header
    len = read(fd, logo_addr, 512);
    if (len < 0)
    {
        if (MTK_LOG_ENABLE == 1) {
            KPOC_LOGI("[libshowlogo: %s %d]read from logo addr for 512B is failed! \n",__FUNCTION__,__LINE__);
        }
        goto error_return;
    }
    // get the image
    len = read(fd, logo_addr, LOGO_BUFFER_SIZE - 512);
    if (len < 0)
    {
        if (MTK_LOG_ENABLE == 1) {
            KPOC_LOGI("[libshowlogo: %s %d]read from logo addr for buffer is failed! \n",__FUNCTION__,__LINE__);
        }
        goto error_return;
    }
    close(fd);
    //set_anim_version 改变了show_animationm_ver的值
    //pinfo[0] 是代表图片量多少, pinfo[1]代表总图片size
    if (show_animationm_ver > 0)
    {
        unsigned int *pinfo = (unsigned int*)logo_addr;
        if (MTK_LOG_ENABLE == 1) {
            KPOC_LOGI("[libshowlogo: %s %d]pinfo[0]=%d, pinfo[1]=%d\n", __FUNCTION__,__LINE__, pinfo[0], pinfo[1]);
        }

        if ((show_animationm_ver == VERION_WIRELESS_CHARGING_ANIMATION) && (pinfo[0] < ANIM_V2_LOGO_NUM))
        {
            set_anim_version(VERION_NEW_ANIMATION);
        }
		//对log数量进行判断,如果是小于39个,就采用旧的动画模式
		
		
        if (pinfo[0] < ANIM_V1_LOGO_NUM)
        {
            kernel_logo_position = ANIM_V0_LOGO_NUM - 1;
            set_anim_version(VERION_OLD_ANIMATION);
        }
        
    }
    if (MTK_LOG_ENABLE == 1) {
        KPOC_LOGI("[libshowlogo: %s %d]show_animationm_ver =  :%d",__FUNCTION__,__LINE__ ,show_animationm_ver);
    }
    return;

error_return:
    if(fd >= 0)
    {
        close(fd);
    }
    free_fstab();
    sleep(3);
    error_flag = 1;
    if (MTK_LOG_ENABLE == 1) {
        KPOC_LOGI("[libshowlogo: %s %d] error return !!!\n",__FUNCTION__,__LINE__);
    }
    // to prevent interlace operation with MD reset
}

至此图片的初始化结束,总结的来说就是为了获取到logo.bin文件的地址logo_addr,而logo的文件是有哪些呢?

alps\vendor\mediatek\proprietary\bootable\bootloader\lk\dev\logo\rules.mk

RESOURCE_OBJ_LIST +=   \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_battery.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_low_battery.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_charger_ov.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_0.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_1.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_2.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_3.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_4.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_5.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_6.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_7.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_8.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_9.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_percent.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_01.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_02.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_03.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_04.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_05.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_06.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_07.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_08.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_09.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_10.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_01.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_02.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_03.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_04.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_05.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_06.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_07.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_08.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_09.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_10.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_bg.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_img.raw \
            $(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_100.raw

这里总37张图片,再加上lk和boot的logo  logo.bin解析后所有的图片就是39张。图片的数量和图片的顺序很总要,后面动画的显示就是根据电池电量来加载第几张图片,一旦顺序错乱就会产生图片加载问题。

5.

void charging_control()
{
	int ret = 0;
	pthread_attr_t attr, attrd, attrl;
	pthread_t uevent_thread, draw_thread, light_thread;

	//charging led control 充电led灯控制
	if (!is_charging_source_available()) {
		lights_exit();
	}

	pthread_mutex_init(&mutexlstate, NULL);

	pthread_mutex_init(&mutex, NULL);
	pthread_cond_init(&cond, NULL);

	pthread_attr_init(&attr);
	pthread_attr_init(&attrd);
	pthread_attr_init(&attrl);

	inDraw = 0;

	ret = pthread_create(&uevent_thread, &attr, uevent_thread_routine, NULL);//创建一个event线程
	if (ret != 0) 
	{
		KPOC_LOGI("create uevt pthread failed.\n");
		exit_charger(EXIT_ERROR_SHUTDOWN);
	}

	firstTime = 1;
	ret = pthread_create(&draw_thread, &attrd, draw_thread_routine, NULL);//创建一个充电线程
	if (ret != 0) 
	{
		KPOC_LOGI("create draw pthread failed.\n");
		exit_charger(EXIT_ERROR_SHUTDOWN);
	}
}

6.

static void* draw_thread_routine(__attribute__((unused))void *arg)
{
	int i, bc, bc_offset = 0;
	int fd_fb = -1, err =0;
	char buf[PROPERTY_VALUE_MAX];
	char filename[32] = {0};
	
	do {
		KPOC_LOGI("draw thread working2...\n");
        // move here to avoid suspend when syncing with surfaceflinger

        if(firstTime){
            // make sure charging source online when in KPOC mode
            // add 2s tolerance
            if(wait_until(is_charging_source_available, 
                        charging_source_waiting_duration_ms,
                        charging_source_waiting_interval_ms))
            {
                KPOC_LOGI("wait until charging source available\n");
            }else{
                KPOC_LOGI("charging source not available for %d ms at KPOC starup\n",
                        charging_source_waiting_duration_ms);
            }
            firstTime = 0;
        }

		inDraw = 1;

		// check the bc offest value
		bc = get_capacity();
//开始画充电动画
		draw_with_interval(bootlogo_show_charging, bc, nChgAnimDuration_msec, nCbInterval_msec);
		stop_backlight();

        // @@@ draw fb again to refresh ddp
        bootlogo_show_charging(bc, 1);

		/* make fb blank */
		snprintf(filename, sizeof(filename), "/dev/graphics/fb0");
		fd_fb = open(filename, O_RDWR);
		if (fd_fb < 0) {
			KPOC_LOGI("Failed to open fb0 device: %s", strerror(errno));
		}
		err = ioctl(fd_fb, FBIOBLANK, FB_BLANK_POWERDOWN);
		if (err < 0) {
			KPOC_LOGI("Failed to blank fb0 device: %s", strerror(errno));
		}
		if (fd_fb >= 0)
			close(fd_fb);
		request_suspend(true);

		inDraw = 0;

        pthread_mutex_lock(&mutex);
		pthread_cond_wait(&cond, &mutex);
		pthread_mutex_unlock(&mutex);
	} while(1);
	pthread_exit(NULL);
	return NULL;
}

7.根据电池电量的不同,显示不同的充电动画,低于10%的电池容量显示低电充电,10%-90%就是一般 100% 显示一张充满点的图片

void bootlogo_show_charging(int capacity, int cnt)
{
    KPOC_LOGI("[ChargingAnimation: %s %d]%d, %d",__FUNCTION__,__LINE__, capacity, cnt);

    if (get_battnotify_status())
    {
        KPOC_LOGI("[ChargingAnimation: %s %d] show_charger_error_logo, get_battnotify_status()= %d \n",__FUNCTION__,__LINE__, get_battnotify_status());
        show_charger_ov_logo();
        return;
    }
    if (showLowBattLogo)
    {
        KPOC_LOGI("[ChargingAnimation: %s %d] show_low_battery , showLowBattLogo = %d \n",__FUNCTION__,__LINE__,showLowBattLogo);
        show_low_battery(); //低电充电
        return;
    }
    show_battery_capacity(capacity);//显示充电容量
}

 

8.show_animation_common.c    show_battery_capacity ->fill_animation_battery_by_ver->fill_animation_battery_new

void fill_animation_battery_new(int capacity, void *fill_addr, void * dec_logo_addr, void * logo_addr, LCM_SCREEN_T phical_screen)
{
    if (MTK_LOG_ENABLE == 1) {
        KPOC_LOGI("[show_animation_common  fill_animation_battery_new: %s %d]capacity : %d\n",__FUNCTION__,__LINE__, capacity);
    }
    //充电容量是100%的情况
    if (capacity >= 100) {
        //show_logo(37); // battery 100
        //FULL_BATTERY_INDEX=37
        fill_animation_logo(FULL_BATTERY_INDEX, fill_addr, dec_logo_addr, logo_addr,phical_screen);

    } 
	//充电容量小于10%的情况
	else if (capacity < 10) {
        if (MTK_LOG_ENABLE == 1) {
            KPOC_LOGI("[show_animation_common: %s %d]charging_low_index = %d\n",__FUNCTION__,__LINE__, charging_low_index);
        }
        charging_low_index ++ ;
   //LOW_BAT_ANIM_START_0=25  NUMBER_PIC_PERCENT=14  NUMBER_PIC_START_0=4
    //充电log
        fill_animation_logo(LOW_BAT_ANIM_START_0 + charging_low_index, fill_addr, dec_logo_addr, logo_addr,phical_screen);
         //充电动画主题画面
		fill_animation_number(NUMBER_PIC_START_0 + capacity, 1, fill_addr, logo_addr, phical_screen);
//充电百分比
       fill_animation_dynamic(NUMBER_PIC_PERCENT, percent_location_rect, fill_addr, percent_pic_addr, logo_addr, phical_screen);

        if (charging_low_index >= 9) charging_low_index = 0;

    }
    //除了上述两种情况的其他情况
    else {

        unsigned int capacity_grids = 0;
        static RECT_REGION_T battery_rect = {CAPACITY_LEFT,CAPACITY_TOP,CAPACITY_RIGHT,CAPACITY_BOTTOM};
       
        if (MTK_LOG_ENABLE == 1) {
            KPOC_LOGI("[show_animation_common: %s %d]capacity_grids : %d,charging_animation_index = %d\n"
                     ,__FUNCTION__,__LINE__, capacity_grids,charging_animation_index);
        }

        //background
        fill_animation_logo(ANIM_V1_BACKGROUND_INDEX, fill_addr, dec_logo_addr, logo_addr,phical_screen);
      
        fill_animation_line(ANIM_LINE_INDEX, capacity_grids, fill_addr,  logo_addr, phical_screen);
		
		//fill_animation_number(NUMBER_PIC_START_0 + (capacity/10), 0, fill_addr, logo_addr, phical_screen);
	  

		 //fill_animation_number(NUMBER_PIC_START_0 + (capacity%10), 1, fill_addr, logo_addr, phical_screen);
         //fill_animation_dynamic(NUMBER_PIC_PERCENT, percent_location_rect, fill_addr, percent_pic_addr, logo_addr, phical_screen);


         if (capacity <= 90)
         {
         
          if (MTK_LOG_ENABLE == 1) {
            KPOC_LOGI("[show_animation_common: %s %d]capacity : %d,charging_animation_index = %d\n"
                     ,__FUNCTION__,__LINE__, capacity,charging_animation_index);
        }
            RECT_REGION_T top_animation_rect = {TOP_ANIMATION_LEFT, capacity_grids - (TOP_ANIMATION_BOTTOM - TOP_ANIMATION_TOP), TOP_ANIMATION_RIGHT, capacity_grids};
            //top_animation_rect.bottom = capacity_grids;
            //top_animation_rect.top = capacity_grids - top_animation_height;
            charging_animation_index++;
            //show_animation_dynamic(15 + charging_animation_index, top_animation_rect, top_animation_addr);
			
			fill_animation_dynamic(BAT_ANIM_START_0 + charging_animation_index, top_animation_rect, fill_addr,
                            top_animation_addr, logo_addr, phical_screen);

            if (charging_animation_index >= 9) charging_animation_index = 0;
         }
    }

}

   总结:这个函数比较重要,这里面制定了充电动画的显示界面,其实充电动画的图片的显示就是一个画布,fill_animation_logo  fill_animation_number  fill_animation_dynamic 这些函数加载一张张图片,按照画布的方式显示。所以一旦发现出现错位问题就是修改rect的四个顶点。

8.fill_animation_logo->fill_rect_with_content->fill_rect_with_content_by_16bit_argb8888

void fill_rect_with_content_by_16bit_argb8888(unsigned short *fill_addr, RECT_REGION_T rect, unsigned int *src_addr, LCM_SCREEN_T phical_screen)
{
    if (MTK_LOG_ENABLE == 1) {
        KPOC_LOGI("[show_logo_common: %s %d]\n",__FUNCTION__,__LINE__);
    }

    int virtual_width = phical_screen.needAllign == 0? phical_screen.width:phical_screen.allignWidth;
    int virtual_height = phical_screen.height;

    int i = 0;
    int j = 0;

    unsigned short * dst_addr = fill_addr;
    unsigned int * color_addr = src_addr;

    for(i = rect.top; i < rect.bottom; i++)
    {
        for(j = rect.left; j < rect.right; j++)
        {
            switch (phical_screen.rotation)
            {
                case 90:
                    color_addr = src_addr++;
					//翻转90 i j 互换
                    dst_addr = fill_addr + (virtual_width * j  + virtual_width - i - 1);
                    break;
                case 270:
                    color_addr = src_addr++;
                    dst_addr = fill_addr + ((virtual_width * (virtual_height - j - 1)+ i));
                    break;
                case 180:
                    // adjust fill in address
                    color_addr = src_addr++;
					//由于图片是翻转180,virtual_width*virtual_height 开始的位置,每增加一个i 就减去virtual_width*i  
                    dst_addr = fill_addr + virtual_width * (virtual_height - i)- j-1-(virtual_width-phical_screen.width);
                    break;
                default:
                    color_addr = src_addr++;
                    dst_addr = fill_addr + virtual_width * i + j;

            }
            if(11 == phical_screen.blue_offset) {
                *dst_addr = ARGB8888_TO_BGR565(*color_addr);
            } else {
                *dst_addr = ARGB8888_TO_RGB565(*color_addr);
            }

            if((i == rect.top && j == rect.left) || (i == rect.bottom - 1 && j == rect.left) ||
               (i == rect.top && j == rect.right - 1) || (i == rect.bottom - 1 && j == rect.right - 1)){
               	if (MTK_LOG_ENABLE == 1) {
                    KPOC_LOGI("[show_logo_common]dst_addr= 0x%08x, color_addr= 0x%08x, i= %d, j=%d\n", *dst_addr, *color_addr, i , j);
                }
            }
        }
    }
}

总结:上面的函数的意义就是把图片的一个个argb数据映射到framebuffer驱动里面,最后通过ioctl(fb_fd, FBIOPUT_VSCREENINFO,&vinfo)来更新framebuffer驱动的显示。

充电动画比较难点在于图片的位置摆放 

小技巧:1)打开画图软件,选择 查看->缩放->自定义,将图片放到到800%

               2)选择 查看->缩放->显示网格

               这样就可以看到一个一个的像素

确定rect的  left,top,right,bottom   

 

 

 

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值