Выбрать главу

In addition to Power Manager, the kernel supports power management by means of the OEMIdle function. Switching the processor into idle state reduces power consumption to the lowest possible level while retaining the ability to return from the idle state quickly. The processor will return to non-idle state periodically or when interrupts occur, as when it responds to user input or when a device requests access to memory for data transfer.

You can significantly reduce the power consumption of a device if you implement power management properly using Power Manager and OEMIdle, thereby increasing battery life, decreasing operating costs, and extending device lifetime.

Lab 3: Kiosk Mode, Threads, and Power Management

In this lab, you develop a kiosk application and configure a target device to run this application instead of the standard shell. You then extend this application to run multiple threads in parallel in the application process and analyze the thread execution by using the Remote Kernel Tracker tool. Subsequently, you enable this application for power management.

NOTE
Detailed step-by-step instructions

To help you successfully master the procedures presented in this lab, see the document "Detailed Step-by-Step Instructions for Lab 3" in the companion material for this book.

► Create a Thread

1. Using the New Project Wizard, create a new WCE Console Application named HelloWorld. Use the Typical Hello_World Application option.

2. Before the _tmain function, implement a thread function named ThreadProc:

DWORD WINAPI ThreadProc( LPVOID lpParameter) {

 RETAILMSG(1,(TEXT("Thread started")));

 // Suspend Thread execution for 3 seconds

 Sleep(3000);

 RETAILMSG(1,(TEXT("Thread Ended")));

 // Return code of the thread 0,

 // usually used to indicate no errors.

 return 0;

}

3. By using the CreateThread function, start a thread:

HANDLE hThread = CreateThread( NULL, 0, ThreadProc, NULL, 0, NULL);

4. Check the returned value of CreateThread to verify that the thread was created successfully.

5. Wait for the thread to reach the end of the thread function and exit:

WaitForSingleObject(hThread, INFINITE);

6. Build the run-time image and download it to the target device.

7. Launch Remote Kernel Tracker and analyze how threads are managed on the system.

8. Start the HelloWorld application and follow the thread execution in the Remote Kernel Tracker window, as illustrated in Figure 3–11.

Figure 3-11 Tracking thread execution in Remote Kernel Tracker tool

► Enable Power Management Notification Messages

1. Continue to use the HelloWorld application in Visual Studio.

2. Generate power-management notifications in more frequent intervals by going into the subproject registry settings and setting the registry entry for the UserIdle timeout in AC power mode (ACUserIdle) to five seconds:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\Timeouts]

 "ACUserIdle"=dword:5 ; in seconds

3. In the ThreadProc function, create a message queue object:

// Size of a POWER_BROADCAST message.

DWORD cbPowerMsgSize =

 sizeof POWER_BROADCAST + (MAX_PATH * sizeof TCHAR);

// Initialize our MSGQUEUEOPTIONS structure.

MSGQUEUEOPTIONS mqo;

mqo.dwSize = sizeof(MSGQUEUEOPTIONS);

mqo.dwFlags = MSGQUEUE_NOPRECOMMIT;

mqo.dwMaxMessages = 4;

mqo.cbMaxMessage = cbPowerMsgSize;

mqo.bReadAccess = TRUE;

//Create a message queue to receive power notifications.

HANDLE hPowerMsgQ = CreateMsgQueue(NULL, &mqo);

if (NULL == hPowerMsgQ) {

 RETAILMSG(1, (L"CreateMsgQueue failed: %x\n", GetLastError()));

 return -1;

}

4. Request to receive notifications from Power Manager and check the received messages:

// Request power notifications

HANDLE hPowerNotifications = RequestPowerNotifications(hPowerMsgQ,

 PBT_TRANSITION | PBT_RESUME | PBT_POWERINFOCHANGE);

DWORD dwCounter = 20;

// Wait for a power notification or for the app to exit

while(dwCounter-- &&

 WaitForSinglObject(hPowerMsgQ, INFINITE) == WAIT_OBJECT_0) {

 DWORD cbRead;

 DWORD dwFlags;

 POWER_BROADCAST *ppb =

  (POWER_BROADCAST*) new BYTE[cbPowerMsgSize];

 // loop through in case there is more than 1 msg.

 while(ReadMsgQueue(hPowerMsgQ, ppb, cbPowerMsgSize,

  &cbRead, 0, &dwFlags)) {

  switch(ppb->Message) {

  case PBT_TRANSITION: {

   RETAILMSG(1,(L"Notification: PBT_TRANSITION\n"));

   if(ppb->Length) {

    RETAILMSG(1,(L"SystemPowerState: %s\n", ppb->SystemPowerState));

   }

   break;

  }

  case PBT_RESUME: {

   RETAILMSG(1,(L"Notification: PBT_RESUME\n"));

   break;

  }

  case PBT_POWERINFOCHANGE: {

   RETAILMSG(1,(L"Notification: PBT_POWERINFOCHANGE\n"));

   break;

  }

  default:

   break;

  }

 }

 delete[] ppb;

}

5. Build the application and rebuild the run-time image.

6. Start the run-time image.

7. You generate user activity by moving the mouse cursor. After five seconds of inactivity, Power Manager should notify the application, as illustrated in Figure 3-12.

Figure 3-12 Received Power Management notifications

► Enable Kiosk Mode

1. Create a WCE Application named Subproject_Shell using the Subproject Wizard. Use the Typical Hello_World Application option.

2. Before the first LoadString line, add a SignalStarted instruction.

// Initialization complete,

// call SignalStarted...

SignalStarted(_wtol(lpCmdLine));

3. Build the application.

4. Add a registry key in the subproject .reg file to launch the application at startup. Add the following lines, which create the corresponding Launch99 and Depend99 entries: