Backlight Management


Many Windows Embedded CE device drivers have a defined interface: they can be stream interface driver with a well defined MDD/PDD layer like audio drivers; or drivers which have a  MDD/PDD layer but do not expose a stream interface, like touch screen drivers; another type of device driver is network adapter miniport drivers which must implement some defined functions to interact with NDIS; and there are other examples.

There is no specification about how a backlight driver has to be designed so you have to design it yourself, maybe taking a look to implementations of the various BSP’s shipped with Platform Builder (for example, in VOIP_PXA270 BSP folder you can find a backlight stream interface driver which has been implemented with a MDD/PDD design in mind).

A simple backlight management can be embedded in the display device driver: the code which handles the power IOCTL’s
could turn off the backlight if the display is requested to go to D4 state and turn it on for higher consumption power states; n
evertheless this does not handle all the options that Windows CE control panels offer to the user.

Despite of what the documentation says you have nothing special to do to include backlight support in the control panel since it’s included by default; possibly you have to modify %_WINCEROOT%\PUBLIC\CEBASE\OAK\MISC\wceshellfe.bat if you do not want to support the backlight user interface removing backlight from %CPLMAIN_COMPONENTS% environment variable.

The Screen control panel applet allows to configure the backlight behaviour with different settings when the device is powered by an AC supply or when it’s powered by a battery. In both cases the user can select to keep the backlight always on or to turn it off after a specified amount of time that the device is not in use (on WM devices you can decide to turn on the backlight if the user taps the screen or presses a button).

Every time the user changes one of these settings the screen control panel applet saves it to the registry under [HKEY_CURRENT_USER\ControlPanel\Backlight] key (note that the settings are per user).
Registry values are defined in %_WINCEROOT%\PUBLIC\WCESHELLFE\OAK\CTLPNL\CPLMAIN\regcpl.h and the most relevant are the following:

“UseBattery”=dword             ;if ‘1’ turn off the backligh after “BatteryTimeout” seconds
“UseExt”=dword:                   ;if ‘1’ turn off the backligh after “ACTimeout” seconds
“BatteryTimeout”=dword:X ;backlight timeout in seconds
“ACTimeout”=dword:Y        ;backlight timeout in seconds

In addition when a value is modified the screen control panel applet sets the  named event “BackLightChangeEvent” to warn about the change.

If you want to expose custom or advanced backlight settings to the user you can implement an advanced backlight control panel applet (for example I did it to allow the user to adjust the backlight level moving a trackbar): the applet must be implemented in a DLL which exports a function with this name and prototype:

BOOL BacklightAdvApplet(
  HWND hDlg
);

If you add to the backlight registry key [HKEY_CURRENT_USER\ControlPanel\BackLight] the string value “AdvancedCPL” which holds the name of the DLL which implements the applet, the screen control panel applet will show an ‘Advanced…’ button in the backlight tab. When the user clicks the button the BacklightAdvApplet function will be called.
You can find a sample advanced applet under %_WINCEROOT%\PUBLIC\WCESHELLFE\OAK\CTLPNL\ADVBACKLIGHT.

Instead of the simple backlight management decribed in the first paragraph, the following code shows as a thread can be used to manage the backlight taking in account the user settings from the control panel.

 //Warning: this code has not be tested; for simplicity there's no error handling or check on functions return values 
#include <windows.h>
#include <ceddk.h>
#define REGISTRY_CHANGE_EVENT_SZ _T("BackLightChangeEvent")  
#define USER_ACTIVITY_EVENT_SZ  _T("PowerManager/UserActivity_Active")
 
#define USER_ACTIVITY_EVENT  0
#define POWER_CHANGE_EVENT  1
#define REGISTRY_CHANGE_EVENT 2  
 
//Helper function to retrieve values from [HKEY_CURRENT_USER\ControlPanel\Backlight]; not implemented
BOOL GetRegistrySettings(DWORD * pdwUseExt, DWORD * pdwUseBattery, DWORD * pdwACTimeout, DWORD * pdwBatteryTimeout);
//Helper function to enable/disable the backlight; returns the backlight status just set; not implemented
BOOL EnableBacklight(BOOL fOn);
DWORD WINAPI BacklightControlThread(LPVOID lpParam)
{
 //Backlight timeout
 DWORD      dwBacklightTimeout; 
 //Current power status, AC / battery
 BOOL      fACLineStatus;  
 //Current backlight status 
 BOOL      fBacklightOn; 
 //Current settings
 DWORD      dwUseExt, dwUseBattery, dwACTimeout, dwBatteryTimeout;
 //
 DWORD      dwWaitStatus, dwBytesRead, dwFlags;
 //For power status change notifications
 MSGQUEUEOPTIONS    MsgQueueOpt;
 UCHAR      PowerInfoBuffer[sizeof(POWER_BROADCAST)+sizeof(PBT_POWERINFOCHANGE)];
 PPOWER_BROADCAST   pPowerInfo = (PPOWER_BROADCAST)PowerInfoBuffer;
 POWER_BROADCAST_POWER_INFO  *ppbpi;
 //Handles to the various events we wait on
 HANDLE       hEvents[3];
 SYSTEM_POWER_STATUS_EX  PowerStatus;
 
 
 //Enable the backlight at the beginning
 fBacklightOn = EnableBacklight(TRUE);
 
 //Get the current power supply status
 GetSystemPowerStatusEx(&PowerStatus,TRUE);
 
 fACLineStatus = (PowerStatus.ACLineStatus  & AC_LINE_ONLINE) ? TRUE : FALSE; 
 
 //Get the backlight settings
 GetRegistrySettings(&dwUseExt, &dwUseBattery, &dwACTimeout, &dwBatteryTimeout);
 //Evaluate the timeout
 dwBacklightTimeout = (fACLineStatus ? dwUseExt : dwUseBattery) ?  //Check if we must turn off according to power supply
  (fACLineStatus ? dwACTimeout : dwBatteryTimeout) :      //Set the timeout if we must turn off
  INFINITE;               //Otherwise set user activity timeout to INFINITE
 //Handle to user activity event signaled by the power manager.
 hEvents[USER_ACTIVITY_EVENT] = CreateEvent(NULL, FALSE, FALSE, USER_ACTIVITY_EVENT_SZ); 
 //Handle to notification for power status change
 MsgQueueOpt.dwSize = sizeof(MSGQUEUEOPTIONS);
 MsgQueueOpt.dwFlags =  MSGQUEUE_NOPRECOMMIT |  MSGQUEUE_ALLOW_BROKEN;
 MsgQueueOpt.dwMaxMessages = 0;
 MsgQueueOpt.cbMaxMessage = sizeof(POWER_BROADCAST) + sizeof(PBT_POWERINFOCHANGE);
 MsgQueueOpt.bReadAccess = TRUE;
 hEvents[POWER_CHANGE_EVENT] = CreateMsgQueue(NULL,&MsgQueueOpt);
 RequestPowerNotifications(hEvents[POWER_CHANGE_EVENT],PBT_POWERINFOCHANGE);
 
 //Handle to registry change event. Note that we use CreateEvent, not OpenEvent, since the screen control panel applet
 //actually creates the event only when it needs to set it then closes it
 hEvents[REGISTRY_CHANGE_EVENT] = CreateEvent(NULL, FALSE, FALSE, REGISTRY_CHANGE_EVENT_SZ);
 
 while(1)
 {
  dwWaitStatus = WaitForMultipleObjects(_countof(hEvents), hEvents, FALSE, 
   (dwBacklightTimeout != INFINITE) ? dwBacklightTimeout*1000 : INFINITE);
   
  switch(dwWaitStatus)
  {
   //user activity timeout elapsed, turn off the backlight if it's on
   case WAIT_TIMEOUT:
   
    if(fBacklightOn)
     fBacklightOn = EnableBacklight(FALSE);
    break;
    
   //user activity, turn on the backlight if it's off 
   case WAIT_OBJECT_0 + USER_ACTIVITY_EVENT:
   
   
    if(!fBacklightOn)
     fBacklightOn = EnableBacklight(TRUE);
    
    break;
    
   //power change notification    
   case WAIT_OBJECT_0 + POWER_CHANGE_EVENT:
   
    //Get information about the power supply state
    ReadMsgQueue(hEvents[POWER_CHANGE_EVENT],&pPowerInfo,sizeof(PowerInfoBuffer),&dwBytesRead, 0, &dwFlags);
    ppbpi = (PPOWER_BROADCAST_POWER_INFO) &pPowerInfo->SystemPowerState[0];
    fACLineStatus = ppbpi->bACLineStatus;
    
    //Evaluate the timeout
    dwBacklightTimeout = (fACLineStatus ? dwUseExt : dwUseBattery) ? 
       (fACLineStatus ? dwACTimeout : dwBatteryTimeout) :   
       INFINITE;            
       
    //Consider a change in power supply as user activity so turn on the backlight      
    if(!fBacklightOn)
     fBacklightOn = EnableBacklight(TRUE);
     
    break;
    
   //registry change notification    
   case WAIT_OBJECT_0 + REGISTRY_CHANGE_EVENT:
   
    //Get the new backlight settings
    GetRegistrySettings(&dwUseExt, &dwUseBattery, &dwACTimeout, &dwBatteryTimeout);
   
    //Evaluate the timeout
    dwBacklightTimeout = (fACLineStatus ? dwUseExt : dwUseBattery) ? 
       (fACLineStatus ? dwACTimeout : dwBatteryTimeout) :   
       INFINITE; 
       
    //Enable the backlight if it's off       
    if(!fBacklightOn)
     fBacklightOn = EnableBacklight(TRUE);       
   
    break;
   case WAIT_FAILED:
   default:
    ;
  }
 }
}   
Advertisements
This entry was posted in Windows Embedded CE and tagged , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s