Posts tagged ‘android’

Android 手机电源管理实例 – milestone

MOTO Milestone (omap)HTC tattoo (msm7225)HTC Magic (msm7201A)某手机(保密)(msm7227)
开机过程200ma-1000ma200ma-500ma
HSDPA 联网700ma500ma
idle, 屏幕最暗, 黑色背景,键灯关44ma13ma33ma60ma
idle, 屏幕中等, 黑色背景,键灯关69ma64ma73ma88ma
idle, 屏幕最亮, 黑色背景,键灯关104ma97ma135ma120ma
idle, 屏幕最暗, 动态桌面,键灯关330ma
idle, 屏幕中等, 动态桌面,键灯关350ma
idle, 屏幕最亮, 动态桌面,键灯关450ma
idle, 屏幕最暗, 白背景,键灯关51ma
idle, 屏幕中等, 白背景,键灯关92ma
idle, 屏幕最亮, 白背景,键灯关167ma
照相机预览400ma-500ma(1G)
325ma-350ma(550M)
210ma-260ma295ma-334ma
录制音频(开屏)107ma-112ma
录制音频(关屏)43ma-59ma
录制视频500ma-700ma(1G)
427ma-558ma(550M)
260ma-360ma360ma-390ma
google maps(gps开)540ma-750ma
浏览网页(HSDPA)(有数据链接时)400ma-600ma
浏览网页(EDGE)(有数据链接时)200ma-500ma
开屏,放mp3,耳机90ma-120ma168ma-220ma285ma
关屏, 放mp3,耳机30ma-50ma93ma-112ma210ma
开屏, 放mp4,耳机(放自己拍摄的)250ma-300ma300ma-327ma
开启g-sensro和gps320ma
wifi扫描时150ma
开led闪光灯(长亮)50ma(单独计算)
虚拟按键led20ma(单独计算)14ma
GSM通话(开接近)350ma-450ma
suspend(关屏进入休眠)2ma1ma1ma2ma

相关日志

android驱动之虚拟按键

1    背景

nexus one工业设计简洁,类似于iphone只有一个按键的设计,只有中间的一个轨迹球。但是android标准键盘是有 HOME,MENU,BACK,SEARCH等,但是同时要保持工业设计。nexus one是这样解决问题的,显示屏是800X480,但是在电容触摸屏是8xx*480的就是比800要大的地方就变成了虚拟按键,模拟了android标准按键。

2    方案

要实现,虚拟按键,在android里面是靠两层协助实现,底层要把虚拟按键在比显示屏多出的地方规定好虚拟按键的位置大小以及键值等,给上层一文件接口。上层java层启动一个服务来读取这一区域的按键响应,这样就是大体的架构。具体实现如下:

2.1    底层虚拟按键功能实现方案

简而言之,就是在内核中把虚拟按键的所有信息给上层给出,用什么方式?就是用sys文件系统的方式,sys文件系统的路径是约定好的所以代码如下实现。给出信息的协议格式是一段连续的字符串,每个按键有六项分别用冒号分割,按键按键之间也是用冒号分割,六项按顺序分别是:

键类型:键值:按键区域中心x坐标:按键区域中心y坐标:按键区域宽:按键区域高

arch/arm/mach-msm/board-mahimahi.c

static ssize_t mahimahi_virtual_keys_show(struct kobject *kobj,
			       struct kobj_attribute *attr, char *buf)
{
	if (system_rev > 2) {
		/* center: x: back: 55, menu: 172, home: 298, search 412, y: 835 */
		return sprintf(buf,
			__stringify(EV_KEY) ":" __stringify(KEY_BACK)  ":55:835:90:55"
		   ":" __stringify(EV_KEY) ":" __stringify(KEY_MENU)   ":172:835:125:55"
		   ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME)   ":298:835:115:55"
		   ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":412:835:95:55"
		   "\n");
	} else {
		/* center: x: home: 55, menu: 185, back: 305, search 425, y: 835 */
		return sprintf(buf,
			__stringify(EV_KEY) ":" __stringify(KEY_HOME)  ":55:835:70:55"
		   ":" __stringify(EV_KEY) ":" __stringify(KEY_MENU)   ":185:835:100:55"
		   ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK)   ":305:835:70:55"
		   ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":425:835:70:55"
		   "\n");
	}
}
 
static struct kobj_attribute mahimahi_virtual_keys_attr = {
	.attr = {
		.name = "virtualkeys.synaptics-rmi-touchscreen",
		.mode = S_IRUGO,
	},
	.show = &mahimahi_virtual_keys_show,
};
 
static struct attribute *mahimahi_properties_attrs[] = {
	&mahimahi_virtual_keys_attr.attr,
	NULL
};
 
static struct attribute_group mahimahi_properties_attr_group = {
	.attrs = mahimahi_properties_attrs,
};
 
struct kobject *properties_kobj;
 
properties_kobj = kobject_create_and_add("board_properties", NULL);
if (properties_kobj)
	ret = sysfs_create_group(properties_kobj,
					 &mahimahi_properties_attr_group);
if (!properties_kobj || ret)
	pr_err("failed to create board_properties\n");

2.2    JAVA上层方案

Java层主要是读取按键信息,然后经过一定的算法,来识别虚拟按键,基本不需要修改,但最好还是熟悉java层的架构这样出问题的时候利于定位
frameworks/base/services/java/com/android/server/KeyInputQueue.java

/*这是虚拟按键的类里面包括了VirtualKey所用到的成员变量和按键定位方法*/
    static class VirtualKey {
        int scancode;
        int centerx;
        int centery;
        int width;
        int height;
 
        int hitLeft;
        int hitTop;
        int hitRight;
        int hitBottom;
 
        InputDevice lastDevice;
        int lastKeycode;
 
        boolean checkHit(int x, int y) {
            return (x >= hitLeft && x <= hitRight                     && y >= hitTop && y <= hitBottom);
        }
 
        void computeHitRect(InputDevice dev, int dw, int dh) {
            if (dev == lastDevice) {
                return;
            }
            if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "computeHitRect for " + scancode
                    + ": dev=" + dev + " absX=" + dev.absX + " absY=" + dev.absY);
 
            lastDevice = dev;
 
            int minx = dev.absX.minValue;
            int maxx = dev.absX.maxValue;
 
            int halfw = width/2;
            int left = centerx - halfw;
            int right = centerx + halfw;
            hitLeft = minx + ((left*maxx-minx)/dw);
            hitRight = minx + ((right*maxx-minx)/dw);
 
            int miny = dev.absY.minValue;
            int maxy = dev.absY.maxValue;
 
            int halfh = height/2;
            int top = centery - halfh;
            int bottom = centery + halfh;
            hitTop = miny + ((top*maxy-miny)/dh);
            hitBottom = miny + ((bottom*maxy-miny)/dh);
        }
    }
/*以下就是与底层接口的函数,如果这个函数和底层接口正常,基本上虚拟按键就能够ok*/
    private void readVirtualKeys(String deviceName) {
        try {
            FileInputStream fis = new FileInputStream(
                    "/sys/board_properties/virtualkeys." + deviceName);
/*这里就是读取kernel给出信息的地方,也就是地层与上层接口的地方,所以整个实现的重点就是这里*/
            InputStreamReader isr = new InputStreamReader(fis);
            BufferedReader br = new BufferedReader(isr, 2048);
            String str = br.readLine();
            if (str != null) {
                String[] it = str.split(":");
                if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "***** VIRTUAL KEYS: " + it);
                final int N = it.length-6;
                for (int i=0; i<=N; i+=6) {
                    if (!"0x01".equals(it[i])) {
                        Log.w(TAG, "Unknown virtual key type at elem #" + i
                                + ": " + it[i]);
                        continue;
                    }
                    try {
                        VirtualKey sb = new VirtualKey();
                        sb.scancode = Integer.parseInt(it[i+1]);
                        sb.centerx = Integer.parseInt(it[i+2]);
                        sb.centery = Integer.parseInt(it[i+3]);
                        sb.width = Integer.parseInt(it[i+4]);
                        sb.height = Integer.parseInt(it[i+5]);
                        if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Virtual key "
                                + sb.scancode + ": center=" + sb.centerx + ","
                                + sb.centery + " size=" + sb.width + "x"
                                + sb.height);
                        mVirtualKeys.add(sb);
                    } catch (NumberFormatException e) {
                        Log.w(TAG, "Bad number at region " + i + " in: "
                                + str, e);
                    }
                }
            }
            br.close();
        } catch (FileNotFoundException e) {
            Log.i(TAG, "No virtual keys found");
        } catch (IOException e) {
            Log.w(TAG, "Error reading virtual keys", e);
        }
    }

2.3    总结

方案基本上就是这样,主要是调试工作可能需要一段时间,还有如果要做虚拟按键,还需要硬件的支持(超过显示区域的触摸屏区域)。本代码基于android 2.1请根据实际情况修改

相关日志

android驱动之jogball

1 简介

JogBall是首款Android手机-HTC Dream上附带的类似轨迹球Trackball的滑轮,通过Jogball用户可以轻松的实现网页的翻页、地图翻

转等操作,这种在手机上增加轨迹球的方式可以取消传统的4维导航键,Jogball并非HTC公司的首例,早在HTC 3300(Dopod P800)就

实现了这项功能,轨迹球操作方式的加入可以实现像电脑上鼠标一样轻松操控。现在jogball基本上算是android手机的标准配置了。

2 框图&架构


2.1 gpio_event子系统

Jogball驱动是由linux代码中的gpio_event子系统实现的。
由以下文件组成:

  • driver/input/misc/gpio_event.c
  • driver/input/misc/gpio_input.c
  • driver/input/misc/gpio_output.c
  • driver/input/misc/gpio_matrix.c
  • driver/input/misc/gpio_axis.c

gpio_event子系统是一个关于gpio的输入设备的通用代码,里面可以包含一般嵌入式设备中需要的键盘阵列和坐标有关的输入等。

2.2 Jogball架构

Jogball是归类于gpio_axis.c中的,是一个相对坐标系,判断电信号的高低来对坐标加或者减一定数值。具体细节在gpio_axis.c中

gpio_axis.c中的结构体初始化是在xxx-borad.c中的,基本架构就是这样,细节在下文叙述。

3 硬件描述


3.1 Jogball机械特性

Jogball是一个基于滚球滚动的输入设备,所以它机械特性也是比较重要,知道他的机械特性,便于我们理解驱动。
Jogball和以前的滚球鼠标比较相似,依靠滚轮的滚动来带动四周的圆柱体旋转。每个圆柱体端头都有一个磁铁,这个磁体铁从横断

面来看就是由N极的扇形和S极的扇形来组成一个圆周。这样当磁铁旋转的时候,N极和S极切换,使霍尔IC产生高低电平。
注意:在滚球旋转时,两个相对方向只有一个方向可以转动,这是为了减化软件编写的一个机械特性。

3.2 Jogball的电气特性

Jogball最重要的电特性就是这个霍尔IC,

霍尔元件的工作原理:所谓霍尔效应,是指磁场作用于载流金属导体、半导体中的载流子时,产生横向电位差的物理现

象。金属的霍尔效应是1879年被美 国物理学家霍尔发现的。当电流通过金属箔片时,若在垂直于电流的方向施加磁场,则金属箔片

两侧面会出现横向电位差。半导体中的霍尔效应比金属箔片中更为明 显,而铁磁金属在居里温度以下将呈现极强的霍尔效应。

所以jogball是旋转磁轴引起磁场的变幻,来产生高低电压的。从而根据机械特性就不难理解jogball的数字输入过程。

3.3 Jogball的原理图

其实jogball只是机械结构,原理图是hall ic的,有兴趣的人在这里下载

4 数据结构

struct hero_axis_info {
        struct gpio_event_axis_info info; /*gpio_event_axis结构的信息*/
        uint16_t in_state;/*记录输入的高低电平信号*/
        uint16_t out_state;/*记录输出的高低电平信号*/
        uint16_t temp_state;/*临时存储高低电平*/
        uint16_t threshold;/*门限值,超过这个值上报给input子系统*/
};
 
struct gpio_event_axis_info {
        /* initialize to gpio_event_axis_func */
        struct gpio_event_info info; /*gpio_event信息*/
        uint8_t  count; /*gpio的数量*/
        uint8_t  type; /* EV_REL or EV_ABS */
        uint16_t code; /*输入键值类型*/
        uint16_t decoded_size; /*gpio 数组的大小*/
        uint16_t (*map)(struct gpio_event_axis_info *info, uint16_t in); /*解析回调函数*/
        uint32_t *gpio; /*gpio端口数组*/
        uint32_t flags; /*调试标值*/
        uint32_t enable_emc_protect_delay; /*保护间隔时间*/
        uint16_t emc_gpio_state; /* 延时中用到gpio_state*/
        atomic_t emc_disable_irqnum;/*延时中用到的屏蔽的中断号*/
};
 
struct gpio_event_info {
        int (*func)(struct input_dev *input_dev,
        struct gpio_event_info *info,
        void **data, int func);
        /*给gpio_event子系统中实现注册到内核中的回调函数*/
        int (*event)(struct input_dev *input_dev,
        struct gpio_event_info *info,
        void **data, unsigned int type,
        unsigned int code, int value); /* out events */
};
 
struct gpio_event_platform_data {
        const char *name;/*名字*/
        struct gpio_event_info **info;/*gpio_event的结构指针*/
        size_t info_count;/*注册到axis中的info 结构体的数量*/
        int (*power)(const struct gpio_event_platform_data *pdata, bool on);/*电源管理回调函数*/
};

5 代码分析

5.1 通用代码

driver/input/misc/gpio_event.c

/*gpio_event基本数据结构*/
struct gpio_event {
        struct input_dev *input_dev;
        const struct gpio_event_platform_data *info;
        struct early_suspend early_suspend;
        void *state[0];
};
 
/*注册给input的回调函数*/
static int gpio_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 
/*调用下层给的回调函数来实现具体的注册*/
static int gpio_event_call_all_func(struct gpio_event *ip, int func)
/*电源管理*/
#ifdef CONFIG_HAS_EARLYSUSPEND
void gpio_event_suspend(struct early_suspend *h)
 
void gpio_event_resume(struct early_suspend *h)
#endif
/*注册*/
static int __init gpio_event_probe(struct platform_device *pdev)
/*注销*/
static int gpio_event_remove(struct platform_device *pdev)
 
static struct platform_driver gpio_event_driver
static int __devinit gpio_event_init(void)
 
static void __exit gpio_event_exit(void)

gpio_event.c:主要是gpio_event子系统的框架

5.2 soc代码

driver/input/misc/gpio_axis.c

struct gpio_axis_state {
struct input_dev *input_dev;/*input设备结构*/
struct gpio_event_axis_info *info; /*坐标系数据结构*/
uint32_t pos; /*位置*/
struct hrtimer emc_hrtimer_delay; /* 延时时间*/
atomic_t atomic_emc_hrtimer_is_run; /*延时的原子变量*/
};
/*上报input数据*/
static void gpio_event_update_axis(struct gpio_axis_state *as, int report)
/*时间处理函数*/
static enum hrtimer_restart emc_progress_hrtimer_handler_func(struct hrtimer *timer)
/*中断处理函数*/
static irqreturn_t gpio_axis_irq_handler(int irq, void *dev_id)
/*给上层的注册回调函数*/
int gpio_event_axis_func(struct input_dev *input_dev, struct gpio_event_info *info, void **data, int func)

5.3 platform代码

例如:/arch/arm/match-msm/board-72×7.c

uint16_t hero_axis_map(struct gpio_event_axis_info *info, uint16_t in)
{
        struct hero_axis_info *ai = container_of(info, struct hero_axis_info, info);
        uint16_t out = ai->out_state;
 
if (nav_just_on) {
        if (jiffies == nav_on_jiffies || jiffies == nav_on_jiffies + 1)
                goto ignore;
        nav_just_on = 0;
}
 
if((ai->in_state ^ in) & 1) /*检测在方向1上有没有数值变化*/
        out--;
if((ai->n_state ^ in) & 2) /*检测在方向1相对方向上有没有数值变化*/
        out++;
ai->;out_state = out;
ignore:
        ai->in_state = in;
if (ai->out_state - ai->temp_state == ai->threshold) {
        ai->temp_state++;
        ai->out_state = ai->temp_state;
} else if (ai->temp_state - ai-out_state == ai->threshold) {
        ai->temp_state--;
        ai->out_state = ai->temp_state;
} else if (abs(ai->out_state - ai->;temp_state) > ai->threshold)
        ai->temp_state = ai->out_state;
 
return ai->temp_state;
}

以上函数,是最终的数据解析函数,也就是把硬件中读出来的数据,转化为实际的位置变化的函数。此函数主要做了差错控制,增加

了程序的鲁棒性和可订制性。

static struct hero_axis_info hero_x_axis = {
        .threshold = 1,
                .info = {
                .info.func = gpio_event_axis_func,
                .count = ARRAY_SIZE(hero_x_axis_gpios),
                .type = EV_REL,
                .code = REL_X,
                .decoded_size = 1U << ARRAY_SIZE(hero_x_axis_gpios),
                .map = hero_axis_map,
                .gpio = hero_x_axis_gpios,
                .flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION /*| GPIOEAF_PRINT_RAW | GPIOEAF_PRINT_EVENT */,
                .enable_emc_protect_delay = 1 * NSEC_PER_MSEC,
        }
};

X轴上的info结构体的初始化

static struct hero_axis_info hero_y_axis = {
        .threshold = 1,
                .info = {
                .info.func = gpio_event_axis_func,
                .count = ARRAY_SIZE(hero_y_axis_gpios),
                .type = EV_REL,
                .code = REL_Y,
                .decoded_size = 1U << ARRAY_SIZE(hero_y_axis_gpios),
                .map = hero_axis_map,
                .gpio = hero_y_axis_gpios,
                .flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION /*| GPIOEAF_PRINT_RAW | GPIOEAF_PRINT_EVENT  */,
                .enable_emc_protect_delay = 1 * NSEC_PER_MSEC,
        }
};

Y轴上的info结构体的初始化

6 备注

在android的framework的代码中识别jogball设备是识别成鼠标的特性的,不仅有坐标还是由按键的,但是驱动中并没有axis中并没

有按键,所以在注册input设备的时候要加入按键的键值。如下代码:
在drivers/input/misc/gpio_axis.c中的gpio_event_axis_func函数中

as->input_dev = input_dev;
as->info = ai;
 
input_set_capability(input_dev, ai->type, ai->;code);
if (ai->type == EV_ABS) {
        input_set_abs_params(input_dev, ai->code, 0,
        ai->decoded_size - 1, 0, 0);
}

input_set_capability(input_dev, ai->type, BT_MOUSE);

本文源码是基于hero手机kernel代码
kernel_hero/arch/arm/mach-msm/board-hero.c
下载地址 http://developer.htc.com/

相关日志

手机操作系统这点事

手机操作系统

手机操作系统

       瘾科技上有这么一则投票,你喜欢那个手机操作系统?那么就去看看结果吧.上图几个手机都是这些操作系统的代表作(现今最牛逼的各个操作系统的代表).

手机操作系统,说来话长,除了iphoneOS和android,都有比较悠久的历史:
windows mobile英文, 中文palm OS英文,中文symbian英文 , 中文;我很早之前就开始关注,也许不能说是关注,就是在其中找乐子.我的历史:首先我得到了一个palm zire 72,被palmOS的快速便捷震撼了(当时可没有multi-touch),就在胖友和蜥蜴的争吵中我了解了windowsCE,也就是现在的mobile ,于是也就有了一段mobile生涯,但是总是win它毕竟是”瘟”啊,在哪都一样!索性symbian一把,symbian确实让人眼前一亮,但是大同小异,没有什么出色的地方(说是实时性比较好,在n73上的龟速,也不是一个palmer能忍受的).接下来的日子Mac OS X的iphone版告诉我,快速和绚丽原来是可以并存的!我也算一代败家…..操作系统是感受过了,手机也换了不少.

研究嵌入式也有一段时间了,这些手机操作系统,确切的说都是嵌入式操作系统,
基本上都是基于ARM的,嵌入式系统是离不开硬件的(android例外).iphoneOS,Android,WebOS都是类UNIX的,前者是unix后两个是linux内核,这就意味这,这几款手机的实时性不好,但是话说回来,手机这东西感觉要实时性没什么用.symbian和windowsMobile是实时性好,但是看来也没强到哪里去…看来现在有些嵌入式的性能指标我们是可以忽略的!现在什么最重要?好了现在看看文章最上面的那张图,得出什么结论了么?

      大屏:这几个手机的屏幕都是属于业界前端的,尤其是索爱的X1更是登峰造极,这要求在整个操作系统的图形系统要很好,硬件也要支持.
      触摸:windows上的触摸技术已经达到了一个新的高度,但是就是现在还没有多点触硬件支持,iphone就不用说了,perfect!palm pre用的屏也是电容式的,webOS同样支持multi-touch.nokia好像也有什么手势技术,不过现在还没有出来就不说了.android实在是太低调了,听说支持mutli-touch就是没有启用….
      网络:这几款手机哪个不是网络应用非常牛,windows和symbian要黯淡许多!看人家palm多直接webOS,不过据我推测,这个webOS的命名是因为在webOS上开发可以用html5,css等web语言得来的把.这就要求操作系统在网络支持上面要越来越强,可怜的windows在这点上我觉得你比不上原生于服务器的linux和BSD–iphoneOS.
      MID:这个名词在2008年着实火疯了,上面几款手机有3款有全键盘,都有硕大的屏幕,全面的网络接入,高性能的硬件,无数的应用软件和大量的开发人员支持,好了现在把前面叙述的特点在脑中想一下,确实能和MID比一下了,以后MID和手机之间的界限将被这些手机和OS变的模糊. 

  这给我们程序员带来了什么呢?
  看看app store中iphone的软件下载量,5个月1万个应用5亿次下载.
有多少人就写了个iphone的软件一夜几万美元.说笑,不过google也如法炮制同样也有app store,palm也有了.给了程序员一次很好的机会,不管是java,web,c程序员都会在移动平台找到他位置的.再说android的山寨方案,这就是嵌入式linux的程序员的机会了,依据不同的硬件移植android,恩,很不错?!

  坐观风云变!自己也要想点什么了.

相关日志