Windows CE carefully monitors and controls the power consumption of the device to ensure maximum battery life. Windows CE makes the following assumptions about typical use when adopting a power management strategy:
Battery life can be severely impacted by PCMCIA and Compact Flash modems and network cards. Serial communications can also drain the battery, especially if the device being communicated with does not supply power for the serial lines. Power Management StatesWindows CE automatically selects the appropriate power management state for a device, depending on how the device is being used. Applications do not have much control over the change from one state to another. A Windows CE device can be in one of four different states:
Your applications must allow Windows CE to change from On to Idle and from Idle to Suspend as appropriate to minimize battery use. This is described in the next two sections. Changing from On to Idle StateWindows CE switches to Idle state when all applications are idle. An application is considered Idle when it has returned control to Windows CE (that is, when it has finished processing a message) or when a thread is suspended, blocked, or sleeping. The switch from On to Idle occurs very quickly, in about 10 microseconds. Try to avoid using loops that do not relinquish control in your applications. These loops stop Windows CE from entering Idle state and, hence, do not allow good power management. The following code sample uses the GetTickCount function (which returns the number of milliseconds that have elapsed since Windows CE started) to pause the application for five seconds. In doing so, your application uses valuable processing time and stops Windows CE from entering the Idle state. DWORD dwTime = GetTickCount(); while(GetTickCount() - dwTime < 5000) { // do nothing } Instead of using the GetTickCount function, use the Sleep function (described in Chapter 5). To pause the application for five seconds, use the following code: //Pause for 5 seconds Sleep(5000); An application does not know when Windows CE changes from the On state to the Idle state, or vice versa. However, if the application is executing code, Windows CE must be in the On state. Changing from Idle to Suspend StateWindows CE enters the Suspend state when one of these situations occurs:
The activity timer monitors the time since the last key press or stylus tap event. When Windows CE detects a key press or tap event, the timer is reset to the value specified by the use in the Control Panel's Power section this value is typically two or three minutes. The activity timer counts down the time since the last key press or tap event occurred, and when the timer reaches 0, Windows CE enters the Suspend state. Applications are not notified when Windows CE enters this state, but device drivers are. Applications are frozen and do not execute when Windows CE is in the Suspend state. They resume execution when the state switches from Suspend to On. Most applications are not affected by entering the Suspend state. The exceptions are those applications that use the Sleep function to pause the current thread for a specified number of milliseconds. Note that the sleep counter does not increment when Windows CE is in Suspend mode, so the thread does not continue executing when Windows CE returns to the On mode. Sometimes you will need to ensure that the device does not enter the Suspend state until some operation (such as serial communications) has completed. You can do this by simulating a keystroke that is ignored by applications using the keybd_event function: keybd_event(VK_F24, 0, KEYEVENTF_KEYUP | KEYEVENTF_SILENT, 0); This function call should be made frequently (say, every 30 seconds) during your critical task. The KEYEVENTF_SILENT flag ensures that the device does not click whenever this function is executed. Monitoring Battery StatusThe function GetSystemPowerStatusEx2 can be used to return battery and power information in a SYSTEM_POWER_STATUS_EX2 structure. As you can see from Listing 13.3, the SYSTEM_POWER_STATUS_EX2 structure contains copious amounts of battery information. However, many devices do not return all the information, and many of the fields are empty or have default values. Listing 13.3 Battery and power status informationvoid Listing13_3() { SYSTEM_POWER_STATUS_EX2 sps; if(GetSystemPowerStatusEx2(&sps, sizeof(sps),TRUE) == 0) cout _T("Could not get power status") endl; else { cout _T("AC Line: "); switch(sps.ACLineStatus) { case AC_LINE_OFFLINE: cout _T("Offline") endl; break; case AC_LINE_ONLINE: cout _T("Online") endl; break; case AC_LINE_BACKUP_POWER: cout _T("Backup power") endl; break; case AC_LINE_UNKNOWN: cout _T("Unknown") endl; break; } cout _T("Battery: "); switch(sps.BatteryFlag) { case BATTERY_FLAG_HIGH: cout _T("High") endl; break; case BATTERY_FLAG_LOW: cout _T("Low") endl; break; case BATTERY_FLAG_CRITICAL: cout _T("Critical") endl; break; case BATTERY_FLAG_CHARGING: cout _T("Charging") endl; break; case BATTERY_FLAG_NO_BATTERY: cout _T("No battery") endl; break; case BATTERY_FLAG_UNKNOWN: cout _T("Unknown") endl; break; } cout _T("BatteryLifePercent: ") sps.BatteryLifePercent endl; cout _T("BatteryLifeTime: ") sps.BatteryLifeTime endl; cout _T("BatteryFullLifeTime : ") sps.BatteryFullLifeTime endl; cout _T("BackupBatteryFlag: "); switch(sps.BackupBatteryFlag) { case BATTERY_FLAG_HIGH: cout _T("High") endl; break; case BATTERY_FLAG_LOW: cout _T("Low") endl; break; case BATTERY_FLAG_CRITICAL: cout _T("Critical") endl; break; case BATTERY_FLAG_CHARGING: cout _T("Charging") endl; break; case BATTERY_FLAG_NO_BATTERY: cout _T("No battery") endl; break; case BATTERY_FLAG_UNKNOWN: cout _T("Unknown") endl; break; } cout _T("BackupBatteryLifePercent : ") sps.BackupBatteryLifePercent endl; cout _T("BackupBatteryLifeTime : ") sps.BackupBatteryLifeTime endl; cout _T("BackupBatteryFullLifeTime : ") sps.BackupBatteryFullLifeTime endl; cout _T("BatteryVoltage : ") sps.BatteryVoltage endl; cout _T("BatteryCurrent : ") sps.BatteryCurrent endl; cout _T("BatteryAverageCurrent : ") sps.BatteryAverageCurrent endl; cout _T("BatteryAverageInterval : ") sps.BatteryAverageInterval endl; cout _T("BatterymAHourConsumed : ") sps.BatterymAHourConsumed endl; cout _T("BatteryTemperature : ") sps.BatteryTemperature endl; cout _T("BackupBatteryVoltage : ") sps.BackupBatteryVoltage endl; cout _T("BatteryChemistry: "); switch(sps.BatteryChemistry) { case BATTERY_CHEMISTRY_ALKALINE: cout _T("Alkaline") endl; break; case BATTERY_CHEMISTRY_NICD: cout _T("NICD") endl; break; case BATTERY_CHEMISTRY_NIMH: cout _T("NIMH") endl; break; case BATTERY_CHEMISTRY_LION: cout _T("LION") endl; break; case BATTERY_CHEMISTRY_LIPOLY: cout _T("LIPOLY") endl; break; case BATTERY_CHEMISTRY_UNKNOWN: cout _T("Unknown") endl; break; } } } The most important values returned in the SYSTEM_POWER_STATUS_EX2 structure are the following:
The third parameter passed to GetSystemPowerStatusEx2 should be TRUE if the function should interrogate the battery status for the latest values, or FALSE if cached information should be used. Cached information can be a few seconds out of date. Powering Off a DeviceIf an application has been performing an unattended task, such as downloading data, it may want to power down the device immediately without waiting for the activity timer to power down the device. In this case, the keybd_event function can be used to simulate the "Off" key being pressed. The "Off" key has the virtual key code "VK_OFF", and Listing 13.4 shows how keybd_event can be called twice to simulate the key being pressed down and then released. Listing 13.4 Powering off a devicevoid Listing13_4() { keybd_event(VK_OFF, 0, KEYEVENTF_SILENT, 0); keybd_event(VK_OFF, 0, KEYEVENTF_KEYUP | KEYEVENTF_SILENT, 0); }
|