显示标签为“wince power management”的博文。显示所有博文
显示标签为“wince power management”的博文。显示所有博文

2008年9月22日星期一

unattended mode reference count

PowerPolicyNotify(PPN_UNATTENDEDMODE, TRUE);
PowerPolicyNotify(PPN_UNATTENDEDMODE, FALSE);
这一对函数的作用,相当于
EnterCriticalSection()
LeaveCriticalSection()
这样类似的成对使用的函数。
实际power manager维护着一个global的reference count,当call PowerPolicyNotify(PPN_UNATTENDEDMODE, TRUE)时,reference count++。
当PowerPolicyNotify(PPN_UNATTENDEDMODE, FALSE),reference count--。

如果万一我们call他们时没有对称,那么系统会怎样?

Power manager参考reference count,如果不等于0,那么他会调度决定进入unattended mode。但是并不是说reference count不等于零,power manager就会让系统永远处于unattended mode,而是会有等待一个超时,如果超时,那么系统还是会进入sleep。同时,这个reference count会在进入sleep后清零,也就是"以前所有的不对称都既往不咎"。

2008年9月18日星期四

Windows Mobile 睡死之谜

Windows Mobile很容易出现"睡死过去"的现象,排除驱动程序的代码问题,那么还是可能"睡死过去"。
今天做了一个实验来模拟在suspend最后那一刻,对文件操作。结果,机器整个hang。

FILE *logFile;
FileSystemPowerFunction(FSNOTIFY_POWER_OFF);

logFile = _tfopen(TEXT("hello.txt"), TEXT("w"));

if (logFile != NULL)
{
_ftprintf(logFile, TEXT("%ld"), 12 );
fclose(logFile);
}

FileSystemPowerFunction(FSNOTIFY_POWER_OFF);是power manager在睡前最后几步必做的事情。而下面的写操作是模拟另一个线程在这个时刻后做写文件的操作。结果就是死亡。
这样的结构在实际开发中很容易形成,要特别小心。

IOCTL_POWER_SET, power manager不为你负责

IOCTL_POWER_SET是驱动程序接收power manager指令的接口。你不要以为power manager会保证每次call你的IOCTL_POWER_SET会保证race condition不发生。换句话说就是IOCTL_POWER_SET可能会被同时call到。
今天我就遇到这样的情况,一个是power manager正常的设置bkl1:到D0,结果另外一个驱动调用了
DevicePowerNotify(_T("bkl1:"), D0,POWER_NAME);
结果我偶然发现Backlight的IOCTL_POWER_SET被同时call到,导致race condition的发生。最后就用Critical Section解决了。

2008年9月12日星期五

display和backlight之间不能不说的事情

我们在windows mobile5/6上写display和backlight驱动程序时候,经常可能会遇到"白屏"的现象。
Display关闭,backlight还是打开,这就是"白屏"。一般情况下,Display和backlight是两个独立的驱动程序,那么看来在关闭屏幕和背光这两个驱动程序是有一定顺序的。
我们先考虑关灯的情况,需要按如下顺序,不可颠倒,颠倒就是"白屏":
1. backlight off 2. display off
再考虑开灯的情况,需要按如下顺序,不可颠倒,颠倒就是"白屏":
1. display on 2. backlight on
从上面可以看出,开灯和关灯动作的顺序是相反的。如果从供电的角度来看,display和backlight有着父子关系,即display是backlight的父亲。display有电,backlight才可能有电。
可是Windows Mobile的power manager在睡觉和唤醒时,对设备驱动的操作是线性的。比如先开display,再开backlight,那么必然也是先关display,再关backlight。因此靠power manager来解决白屏问题是不可能了,需要我们自己处理。
而且实际上由于display和backlight的IClass不同,使得他们位于power manager的两个不同的设备管理列表里,导致backlight的流设备列表一定先被操作到,然后才是display。这样一来和上面提到的关灯的顺序是符合的。开灯的顺序相反!

解决方案一
把backlight放在display驱动中去做,这样简单很多,很多变量可以共享

解决方案二
Backlight和display仍然是两个驱动。那么我们的重点是反转开灯的顺序。可以选择在backlight驱动程序处理IOCTL_POWER_SET的D0时,给display驱动的电源状态设置一个floor(请参考 http://cpuwolf.blogspot.com/2008/09/window-mobile-power-managementdevice.html),先调用SetPowerRequirement(pszDevice, D0, POWER_NAME, NULL, 0);再开启硬件背光。这个结论Microsoft的文档也有,但是她绝对不会告诉你为什么。

2008年9月11日星期四

揭秘window mobile power management关于device power state的管理

hi, I am cpuwolf。今天我就由深入浅的帮你揭开mobile power manager(也就是pm.dll)是如何调度设备的power state。先分析power manager的内部结构,再从API的角度帮你理解power management API的不同。他们是:
DevicePowerNotify()
SetDevicePower()
SetPowerRequirement()
ReleasePowerRequirement()
这几个函数,如果你不听我讲,光想通过看看microsoft的官方文档来理解,那是不可能的!信不信由你。

重要的数据结构

power manager为每一个被管理的设备维护着一个数据结构,它的定义简化后如下:
// this structure describes a power-manageable device
typedef struct _DeviceState_tag {
。。。
CEDEVICE_POWER_STATE curDx; // current official power state (not necessarily supported by the device)
CEDEVICE_POWER_STATE floorDx; // minimum device power state, or PwrDeviceUnspecified
CEDEVICE_POWER_STATE ceilingDx; // maximum device power state, or PwrDeviceUnspecified
CEDEVICE_POWER_STATE setDx; // power state if explicitly set, or PwrDeviceUnspecified
CEDEVICE_POWER_STATE lastReqDx; // last state requested by the device
CEDEVICE_POWER_STATE actualDx; // current actual device power state
CEDEVICE_POWER_STATE pendingDx; // Pending DX for updating
DWORD dwNumPending; // Number of Pending for updating.
。。。
} DEVICE_STATE, *PDEVICE_STATE;
居然有这么多的device power state来影响最后的一个power state的结果。也就是说power manager是个调度中心,当它最后决定某个设备最终该是什么power state(D0/D1/D2/D3/D4)的时候,要参考上面这些成员变量。所以我们第一件事是要搞清楚power manager的调度原则。

power manager的调度原则

设备的电源状态总共有D0,D1,D2,D3,D4 (D0〈D1〈D2〈D3〈D4)。ceilingDx与floorDx听名字就知道是天花板和地板的意思(ceilingDx〈floorDx),人是生活在天花板和地板之间的空间的。在电源管理里面,意思就是天花板和地板之间的电源状态为有效状态。
例如:
ceilingDx=D1
floorDx=D3
那么D0,D4就是power manager不用考虑的状态,D1,D2,D3就是有效的电源状态。


setDx是最厉害的一个状态,它默认是PwrDeviceUnspecified,只要它不是PwrDeviceUnspecified,那么这个设备的最终状态就等于setDx。
那么setDx是谁设置的呢?
从名字我们一猜就知道,那就是SetDevicePower()。也就是说,只要这个函数一出马,那么不管系统当前是什么状态,或者这个设备是什么状态,这个对应的设备会立即切换到你指定的状态。因此,call这个函数的时候一定要三思而后行。白屏现象就很有可能是他造成的。
例如:
SetDevicePower(_T("BKL1:"),POWER_NAME,D4);
这句话就好像在说:“power manager,我命令你把BKL1:变成D4!!”

如果setDx是PwrDeviceUnspecified,那么power manager就开始考虑lastReqDx。lastReqDx的气势就要虚弱很多,也正如microsoft的文档所说,如果你想改变一个设备的系统状态,同时还想争得power manager的同意,不想太强制,那么call DevicePowerNotify()是再合适不过的了。
例如:
DevicePowerNotify(_T("BKL1:"),D4,POWER_NAME);
这句话就好像在说:“power manager,你看我现在把BKL1:变成D4如何?!”
power manager接到这样的请求,它也是需要掂量一下的,那么它的原则是什么呢?只要是有效状态就可以啦!也就是说ceilingDx〈 lastReqDx〈floorDx。
如果ceilingDx=D1,lastReqDx=D0,那么设备最终也只能是D1。
再如floorDx=D3,astReqDx=D4,那么设备最终也只能是D3。
如果 ceilingDx=D1,floorDx=D3,你请求D2,那么设备最终就是D2。

以上原则很简单吧!可是你有没有注意到我没有提到ceilingDx与floorDx是如何确定的。说到这个就不得不说说SetPowerRequirement()和
例如:
SetPowerRequirement(_T("BKL1:"),D1,POWER_NAME,NULL,0);
好像再说在说:“power manager,帮我把BKL1:变成D1”。你觉得呢?当然不是!
其实你的真正意思是在说:“power manager,至少帮我把BKL1:变成D1”。
然后power manager问你,“D0可以么?(背光更亮一点可以么?)”。
然后你会说,“当然也可以。”
从这个对话中,我们可以知道SetPowerRequirement()实际在设置我们的地板-floorDx。至少是floorDx,不能更低了。floorDx的默认值是D4,因此如果你不去call这个函数,那么就没什么限制。

至于ceilingDx
注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\[ on | BacklightOff | Unattended | xxx ]的下面你可以定义:
"bkl1:"=D2
这样的定义,就好像你在规定:“系统在on的时候,bkl1:最高是D2”。所以bkl1:如果是D3,那么也是可以的。这实际就是在定义设备电源状态的天花板-ceilingDx。同时,如果你没有特别为某个设备指定,那么这个设备的ceilingDx就是用注册表项default的定义值。

综上,floorDx,ceilingDx,setDx,lastReqDx这四个值是power manager调度时要参考的重要参数。

设置设备的电源状态

curDx,actualDx是一对,意思非常接近。
curDx是power manager经过调度算法,最后决定的,该设备的电源状态。可是这个状态,此设备不一定支持。设备声明自己所支持的所有状态是通过IOCTL_POWER_CAPABILITIES做到的。因此万一不支持还需要经过mapping,那么mapping的结果就是actualDx,这个结果就直接通过IOCTL_POWER_SET下达给设备驱动。mapping的过程当然就要参考IOCTL_POWER_CAPABILITIES了。

pendingDx和dwNumPending是用于处理竞争问题设计的计数器。

2007年6月21日星期四

Stay in Unattended mode(written by Mike)

I believe the fastest way to get the screen to turn off is this. As soon as your app detects the phone ring, first call:

PowerPolicyNotify(PPN_UNATTENDEDMODE, TRUE);

Then call

PowerPolicyNotify(PPN_POWERBUTTONPRESSED, 0);

Now handle the call. You need to be calling SystemIdleTimerReset(); every 30 seconds to keep the system from falling asleep while you're processing the call.

When the call is over, do:

PowerPolicyNotify(PPN_UNATTENDEDMODE, FALSE);

The first PPN puts the system into a state where, if the power button is pressed, it will turn the screen off but not suspend.

The second PPN simulates the press of the power button. Assuming the screen was on at the time, this will tell the system to suspend, but will instead go to the Unattended (screen off) state because of the first call. (If the screen was off when you did the PowerButtonPressed, it would turn the screen on.)

When you're done with the call, the last PPN tells the system to suspend immediately (as long as there isn't another app in Unattended).

SD卡关于WINCE睡眠的思考

blogs.msdn.com的Mike这样说:
On most devices, the SD hardware is powered down when the system suspends. So it needs to be re-initialized on wakeup. Then, after it is initialized, it needs to find the SD card and mount it. Depending on the SD bus hardware and the particular SD card, this process can take a few seconds.
在大多数的设备上,当系统进入睡眠时,SD设备是断电的。因此当系统醒来时,它需要重新的初始化。很自然地,初始化后,要查找SD卡和挂装文件系统。由于SD设备和SD卡的不同,这个过程需要一些时间。

由此想到以下的测试要求是不合理的:
1.SD卡复制文件时,susend和wakeup系统,不能要求他还能续传
2.Media player在播放SD卡上的音乐文件时,susend和wakeup系统,不能要求还能继续播放

2007年4月3日星期二

优化耗电过程

我们可以不允许系统进入backlight off和suspend,然后看系统能够运行多久。如果这个时间能够增长,再对suspend进行实现,这样就有更长的使用时间了。

2007年3月31日星期六

PowerButton高频率点击

变态的测试人员,居然会把高频率点击powerbutton也变为他们的测试项目。可是更有“高水平”开发人员为了迎合这种测试,“自以为是”对wince的电源状态转换进行改动。比如为了切换速度快,按power button让系统先进入unattended mode,再按power button系统又切到on。的确是切换速度快了很多,但是他们欺骗了用户,让用户以为unattended就是suspend。哈哈,可是问题接踵而来,suspend该有的系统行为,unattend模式怎么可能有,结果更多的bug由然而生。

还有人会说PowerPolicyNotify(PPN_POWERBUTTONPRESSED, 0)不怎么好用,认为SetSystemPowerState好用,可以直接使系统变到自己想要的状态。不要以为看了public下面的code就以为自己了解了PM,光说这“看”与“看”还有区别呢,你到底消化了多少??!

我们是谁?开发人员,我们可以改变用户的习惯,不要惯了他们的“毛病”。我们可以定义如:
1. power button 最高速度一秒按一下
2. 连续按住power button达一秒,才产生一次power button消息

请你们平时多提升一下个人的专业水平,理解软件架构的意义。

2007年3月16日星期五

Windows Mobile Activity timer

Activity Timers也不是什么新鲜东西。这个东东真的很难懂,连续看了MSDN的解释不下20遍,也还是没弄懂怎么回事,说得太抽象了。希望这里我能帮大家有个形象的理解。

我们都知道在PocketPC上,我们点击touch panel,如果机器没有睡觉,那么屏幕就会亮起来。这其实是系统backlight offon的一次电源状态转换,这个动作是由pm.dll来完成的。

那么pm.dll是如何“感知”到这种“user activity”的呢?其实就是这个activity timer

touch panel为例,当有点击事件时,会SetEvent()来通知Pm.dll,这个event的名字由注册表HKEY_LOCAL_MACHINE\System\GWE\ActivityEvent的键值指明,其值一般为PowerManager/ActivityTimer/UserActivity ,这个event是被pm.dll随时“监视”的。也就是说如果你setEventpm.dll就会认为是“user activity”,然后再做相应得电源状态转换。

2007年3月9日星期五

unattended mode不是驱动玩的东西

我们在写wince驱动的时候,千万不要自己去调用PowerPolicyNotify( PPN_UNATTENDEDMODE),永远要记住,整个操作系统中除了驱动程序,更重要的还有应用程序,他们才是上帝,是需求的提交者。
总感觉自己的废话很多,但是无论我重复多少遍,还有很多程序员犯这样的错误。

2007年3月2日星期五

wince电源管理框图


流接口驱动程序总是通过IOCTL接收系统对自己的设置。IOCTL_POWER_SET就是系统把设备的状态设置成D0D1D2D3D4其中之一。可以想象,设备驱动自己如果想主动的改变自己的状态,那么很容易可以在自己的代码中调用自己的IOCTL。可是,如果这样做,设备的状态是不被系统知道的,我们必须通知系统。DevicePowerNotify()就是用于通知系统,再由系统决定当前是否需要改变设备的电源状态。注意,千万不要假设,当你call DevicePowerNotify(),你一定会收到IOCTL_POWER_SET。因为系统会根据应用程序的需求决定当前是否改变设备状态。

2007年2月28日星期三

power消息


Battery驱动程序总是和power management有关。battery当前的状态是由battery驱动主动通过powerpolicynotify()报告给pm.dll的,然后当Pm.dll收到这个消息,它会GetSystemPowerStatusEx2()读取一次电池的状态,如果确实发生改变,pm.dll会发送消息给提出消息通知RequestPowerNotifications()的应用程序

电源管理之 关于电源状态的思考

系统状态的onsuspend是最基本的状态,对于CPU一般就是onsleep两个状态,因此很容易理解。

Backlight off就是关掉背光灯,其他设备都正常运转,此时用户的所有活动(按键,点击触摸屏等)都会通知到pm.dll,使系统状态变回on,同时也由pm.dll调用ioctlIOCTL_POWER_SET把每个设备的状态设置一次。我们可以在控制面板中设置什么时候关掉背光。

Backlight off超时,就会suspend,此时所有的设备进入D3CPU进入等待中断的节能状态。我们可以SystemIdleTimerReset()间隔一段时间重置一下timeout时间,使系统永远都不能suspend,这就是为什么media player可以连续播放音乐,而不至于sleep。你可以注意到这种对电源的需求是由应用程序提出的,而不是驱动程序。

系统一但进入suspend,只有靠hardware中断才能唤醒CPU core,驱动程序可以调用KernelIoControl(IOCTL_HAL_ENABLE_WAKE)来宣告自己是唤醒系统的中断源。我要强调一下,这里的“唤醒”不是使系统变为on,而是系统由suspend变为resumingresuming对应D2,作为用户或者开发者的你,在外面是看不见任何现象的(不会有背光被打开)。如果你想要如SD卡插入系统被唤醒(即系统进入on的状态),需应用程序或驱动程序监视系统进入resuming状态,此时查看唤醒源是什么中断,如果是SD,可以模拟一次application button press,发送PowerPolicyNotify(PPN_APPBUTTONPRESSED0),即可以完全唤醒系统。

Resuming被定义为“最不稳定”的状态。因为当处于其他的任何状态,都可以通过间隔性的调用SystemIdleTimerReset()来保持住当前状态,唯独resuming不可以被保持,15秒之后系统会睡眠。

那么来假想一种需求,如果某个应用程序每隔5分钟需要做一些例如同步的事情。5分钟很长,这个程序还想为系统考虑,节约用电,那么5分钟之内系统可以suspend来节电,5分钟之后通过RTC中断将系统唤醒,做一些“后台”同步的事情,因此这个事不需要用户参与(也就是背光和屏幕可以关闭,同时声音关闭)。这个需求导致了unattended电源状态的产生。在进入resuming状态15秒以后,如果系统发现有程序提出unattended的需求,
PowerPolicyNotify( PPN_UNATTENDEDMODE
TRUE)
PowerPolicyNotify( PPN_UNATTENDEDMODE
FALSE)
那么系统进入unattended电源状态,使机器在不打扰用户的情况下运行。

2007年2月27日星期二

winCE电源管理之 系统状态 与 设备状态

最近一直在看window mobile 5.0的电源管理,试图抓住他们的思想。终于发现光看文档是不会有什么感觉的,非要看代码,然后回来结合文档才知道是怎么回事。

所谓的电源管理(power management),就是让电池驱动的winCE嵌入式系统,能够有尽可能长的使用时间。这里主要想谈谈pocket PC

系统中device.exe是加载大部分驱动程序的进程,wince5.0的电源管理核心代码在pm.dll中,而pm.dll也是device.exe加载的对象。所以这是集中管理的模式,pm.dll承载了绝大多数管理代码。

从软件层面看,电源管理中涉及两种状态:system power statesdevice power states

System power states包括:OnSuspendBacklight offResumingUnattendedUser idle。这是“系统”的状态,也可以理解为CPU的状态或者操作系统得状态。

Device power states包括几个等级:D0D1D2D3D4。这些是winCE管理的“设备”状态,如果你是某个设备的驱动程序员,每个设备都有自己的电源管理模式,最基本的是开和关两个状态,对应D0D4。因此D1D2D3自然就是开与关之间的状态。就是这么简单,不要想复杂了。

“系统”状态和“设备”状态他们之间有系统默认的对应关系,就是说对于一个“系统状态”,系统中所有设备都默认被设置成某个“设备状态”(除非有特殊说明,某些设备可以对应不同的“设备状态”)。on对应D0,即系统在on状态时,所有的设备都是打开的。suspend对应D3,即系统在睡眠的时候,所有设备都被设置为D3Backlight off对应D0,同理所有的设备打开,不过这个状态有特殊说明(要不它如何区别onbacklight off),bkl1:对应D4,即,背光灯关闭,因此backlight off就是其他所有设备打开,bkl1:关闭。同理可以理解其他的系统状态。Suspend对应D3resuming对应D2等等。

整个wince系统就是一个状态机,每个状态现在都可以理解,但是有状态,就有状态转换,在特定条件下的转换。几个系统状态中只有一个状态suspend是比较稳定的,因为其他的几个状态都会经过timeout最后变成suspend。引用wince开发人员Mike Calligaro的话,装有wince的设备就像一个疲劳的看守坟场的保安在值夜班,正托着下垂的眼皮在看电视,偶尔拍他一下,他才醒过来。

WinCE 5.0 power state machine