操作qtopia2.2.0电池图标显示电池电量
想让qtopia2.2.0下的电池图标显示电池的实际状态,一开始不知道怎么操作,在网上也找不到相应的教程,也没有qtopia2.2.0的api文档。刚开始感觉没有办法解决,想了好多替代方法,感觉都不好,最后只好去qtopia2.2.0的源码中去寻找,看看能不能找到点蛛丝马迹(一开始不想去源码里找,感觉太麻烦,但事实证明看源码是一个好方法)。
在qtopia2.2.0下设置程序组下的Plugin Manager软件里可添加和删除屏幕右下角的几个小程序,比如背光调节、音量调节、电池电量等。
在qtopia2.2.0的源码中搜索"battery"(grep "battery*" ./ -nr),
出现次数比较多的源码文件是
/root/work/mini6410/linux/arm-qtopia/qtopia-2.2.0-FriendlyARM/qtopia/src/plugins/applets/batteryapplet/battery.cpp
/root/work/mini6410/linux/arm-qtopia/qtopia-2.2.0-FriendlyARM/qtopia/src/plugins/applets/batteryapplet/batterystatus.cpp
/root/work/mini6410/linux/arm-qtopia/qtopia-2.2.0-FriendlyARM/qtopia/src/settings/light-and-power/light.cpp
打开battery.cpp和batterystatus.cpp可以看到qt对电池图标的变化已经做了很好的支持。
在\arm-qtopia\qtopia-2.2.0-friendlyarm\qtopia\src\libraries\qtopia\Power.cpp中看到如下代码:
1 #include "power.h"
2
3 #include "custom.h"
4
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <fcntl.h>
8 #if defined(Q_OS_LINUX) || defined(_OS_LINUX_)
9 #include <sys/ioctl.h>
10 #include <unistd.h>
11 #endif
12
13 #ifdef QT_QWS_IPAQ_NO_APM
14 #include <linux/h3600_ts.h>
15 #endif
16
17 PowerStatusManager *PowerStatusManager::powerManager = 0;
18 PowerStatus *PowerStatusManager::ps = 0;
19
20 PowerStatusManager::PowerStatusManager()
21 {
22 powerManager = this;
23 ps = new PowerStatus;
24 }
25
26 const PowerStatus &PowerStatusManager::readStatus()
27 {
28 if ( !powerManager ) {
29 (void)new PowerStatusManager;
30 }
31
32 powerManager->getStatus();
33
34 return *ps;
35 }
36
37 // Standard /proc/apm reader
38 bool PowerStatusManager::getProcApmStatus( int &ac, int &bs, int &bf, int &pc, int &sec )
39 {
40 bool ok = false;
41
42 ac = 0xff;
43 bs = 0xff;
44 bf = 0xff;
45 pc = -1;
46 sec = -1;
47
48 FILE *f = fopen("/proc/apm", "r");
49 if ( f ) {
50 //I 1.13 1.2 0x02 0x00 0xff 0xff 49% 147 sec
51 char u;
52 fscanf(f, "%*[^ ] %*d.%*d 0x%*x 0x%x 0x%x 0x%x %d%% %i %c",
53 &ac, &bs, &bf, &pc, &sec, &u);
54 fclose(f);
55 switch ( u ) {
56 case 'm': sec *= 60;
57 case 's': break; // ok
58 default: sec = -1; // unknown
59 }
60
61 // extract data
62 switch ( bs ) {
63 case 0x00:
64 ps->bs = PowerStatus::High;
65 break;
66 case 0x01:
67 ps->bs = PowerStatus::Low;
68 break;
69 case 0x7f:
70 ps->bs = PowerStatus::VeryLow;
71 break;
72 case 0x02:
73 ps->bs = PowerStatus::Critical;
74 break;
75 case 0x03:
76 ps->bs = PowerStatus::Charging;
77 break;
78 case 0x04:
79 case 0xff: // 0xff is Unknown but we map to NotPresent
80 default:
81 ps->bs = PowerStatus::NotPresent;
82 break;
83 }
84
85 switch ( ac ) {
86 case 0x00:
87 ps->ac = PowerStatus::Offline;
88 break;
89 case 0x01:
90 ps->ac = PowerStatus::Online;
91 break;
92 case 0x02:
93 ps->ac = PowerStatus::Backup;
94 break;
95 }
96
97 if ( pc > 100 )
98 pc = -1;
99
100 ps->percentRemain = pc;
101 ps->secsRemain = sec;
102
103 ok = true;
104 } else {
105 ps->bs = PowerStatus::NotPresent;
106 pc = sec = -1;
107 ps->percentRemain = -1;
108 ps->secsRemain = -1;
109 }
110
111
112 return ok;
113 }
114
115 const bool PowerStatusManager::APMEnabled()
116 {
117 int apm_install_flags;
118 FILE *f = fopen("/proc/apm", "r");
119 if ( f ) {
120 //I 1.13 1.2 0x02 0x00 0xff 0xff 49% 147 sec
121 fscanf(f, "%*[^ ] %*d.%*d 0x%x 0x%*x 0x%*x 0x%*x %*d%% %*i %*c",
122 &apm_install_flags);
123 fclose(f);
124
125 if (!(apm_install_flags & 0x08)) //!APM_BIOS_DISABLED
126 {
127 return TRUE;
128 }
129 }
130 return FALSE;
131 }
从以上代码知道了,qt的电源状态信息是从/proc/apm中得到的,那么只要操作/proc/apm,电源图标的状态就会相应改变了。
回到驱动,/proc/apm的创建和操作是在drivers/char/apm-emulation.c中实现的,apm-emulation.c中不仅实现了电源状态的操作还实现了系统的休眠和唤醒,为了做一个测试,只把apm-emulation.c中关于操作/proc/apm的代码复制出来,重新编写一个驱动模块apm-qyh.c,代码如下。
1 /*
2 * bios-less APM driver for ARM Linux
3 * qiaoyihan
4 * adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com)
5 *
6 */
7 #include <linux/module.h>
8 #include <linux/poll.h>
9 #include <linux/slab.h>
10 #include <linux/mutex.h>
11 #include <linux/proc_fs.h>
12 #include <linux/seq_file.h>
13 #include <linux/miscdevice.h>
14 #include <linux/apm_bios.h>
15 #include <linux/capability.h>
16 #include <linux/sched.h>
17 #include <linux/apm-emulation.h>
18 #include <linux/freezer.h>
19 #include <linux/device.h>
20 #include <linux/kernel.h>
21 #include <linux/list.h>
22 #include <linux/init.h>
23 #include <linux/completion.h>
24 #include <linux/kthread.h>
25 #include <linux/delay.h>
26
27 #include <asm/system.h>
28
29
30 static const char driver_version[] = "1.13"; /* no spaces */
31
32 /*
33 * Compatibility cruft until the IPAQ people move over to the new
34 * interface.
35 */
36 static void __apm_get_power_status(struct apm_power_info *info)
37 {
38 info->ac_line_status = 0x00;
39 info->battery_status = 0x01;
40 info->battery_flag = 0x01;
41 info->battery_life = 30;
42 info->time = 135;
43 info->units = 1;
44 }
45
46 /*
47 * This allows machines to provide their own "apm get power status" function.
48 */
49 void (*apm_get_power_status)(struct apm_power_info *) = __apm_get_power_status;
50
51 /*
52 * Arguments, with symbols from linux/apm_bios.h.
53 *
54 * 0) Linux driver version (this will change if format changes)
55 * 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2.
56 * 2) APM flags from APM Installation Check (0x00):
57 * bit 0: APM_16_BIT_SUPPORT
58 * bit 1: APM_32_BIT_SUPPORT
59 * bit 2: APM_IDLE_SLOWS_CLOCK
60 * bit 3: APM_BIOS_DISABLED
61 * bit 4: APM_BIOS_DISENGAGED
62 * 3) AC line status
63 * 0x00: Off-line
64 * 0x01: On-line
65 * 0x02: On backup power (BIOS >= 1.1 only)
66 * 0xff: Unknown
67 * 4) Battery status
68 * 0x00: High
69 * 0x01: Low
70 * 0x02: Critical
71 * 0x03: Charging
72 * 0x04: Selected battery not present (BIOS >= 1.2 only)
73 * 0xff: Unknown
74 * 5) Battery flag
75 * bit 0: High
76 * bit 1: Low
77 * bit 2: Critical
78 * bit 3: Charging
79 * bit 7: No system battery
80 * 0xff: Unknown
81 * 6) Remaining battery life (percentage of charge):
82 * 0-100: valid
83 * -1: Unknown
84 * 7) Remaining battery life (time units):
85 * Number of remaining minutes or seconds
86 * -1: Unknown
87 * 8) min = minutes; sec = seconds
88 */
89 static int proc_apm_show(struct seq_file *m, void *v)
90 {
91 struct apm_power_info info;
92 char *units;
93
94 info.ac_line_status = 0xff;
95 info.battery_status = 0xff;
96 info.battery_flag = 0xff;
97 info.battery_life = -1;
98 info.time = -1;
99 info.units = -1;
100
101 if (apm_get_power_status)
102 apm_get_power_status(&info);
103
104 switch (info.units) {
105 default: units = "?"; break;
106 case 0: units = "min"; break;
107 case 1: units = "sec"; break;
108 }
109
110 seq_printf(m, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
111 driver_version, APM_32_BIT_SUPPORT,
112 info.ac_line_status, info.battery_status,
113 info.battery_flag, info.battery_life,
114 info.time, units);
115
116 return 0;
117 }
118
119 static int proc_apm_open(struct inode *inode, struct file *file)
120 {
121 return single_open(file, proc_apm_show, NULL);
122 }
123
124 static const struct file_operations apm_proc_fops = {
125 .owner = THIS_MODULE,
126 .open = proc_apm_open,
127 .read = seq_read,
128 .llseek = seq_lseek,
129 .release = single_release,
130 };
131
132
133 static int __init apm_init(void)
134 {
135
136 proc_create("apm", 0, NULL, &apm_proc_fops);
137 return 0;
138 }
139
140 static void __exit apm_exit(void)
141 {
142
143 remove_proc_entry("apm", NULL);
144
145 }
146
147 module_init(apm_init);
148 module_exit(apm_exit);
149
150 MODULE_AUTHOR("qiaoyihan");
151 MODULE_DESCRIPTION("Power Status Management");
152 MODULE_LICENSE("GPL");