piprofiler/plugins/PWRplugin/src/PwrPlugin.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 16:45:49 +0300
branchRCL_3
changeset 20 ca8a1b6995f6
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  
*
*/

#include "PwrPlugin.h"
#include <piprofiler/ProfilerTraces.h>

#include <centralrepository.h>
#include <HWRMPower.h>
#include <HWRMLight.h>
#include <hwrm/hwrmpowerdomaincrkeys.h>


// texts for notes
_LIT(KPowerTextLine1, "Power sampler:");
_LIT(KPowerTextLine2, "Failed to start power measurement");
_LIT(KPowerTextErrorSampling, "Error receiving measurement data");
_LIT(KButtonOk, "Ok");

// LITERALS

_LIT8(KSamplingPeriodMs, "sampling_period_ms");

// CONSTANTS
// Use this UID if plugin is PwrPlugin:
const TUid KSamplerPwrPluginUid = { 0x2001E5B9 };

/*
 *
 * class CPwrPlugin implementation
 * 
 */
 
CPwrPlugin* CPwrPlugin::NewL(const TUid /*aImplementationUid*/, TAny* aInitParams)
    {
    LOGTEXT(_L("CPwrPlugin::NewL() - entry"));
    CPwrPlugin* self = new (ELeave) CPwrPlugin();
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop();
    LOGTEXT(_L("CPwrPlugin::NewL() - exit"));
    return self;
    }

CPwrPlugin::CPwrPlugin() :
    iVersionDescriptor(&(this->iVersion[1]),0,19),
    iSamplerType(PROFILER_USER_MODE_SAMPLER)
    {
    iPeriod = 250;
    iSamplerId = PROFILER_PWR_SAMPLER_ID;
    iEnabled = EFalse;
    iPowerListener = NULL;
    LOGTEXT(_L("CPwrPlugin::CPwrPlugin() - konstruktori"));

    }

void CPwrPlugin::ConstructL() 
    {
    LOGTEXT(_L("CPwrPlugin::ConstructL() - entry"));
    // initiate sampler attributes array
    iSamplerAttributes = new(ELeave) CArrayFixFlat<TSamplerAttributes>(1); // only one sampler

    // insert default attributes to array
    InitiateSamplerAttributesL();

    LOGTEXT(_L("CPwrPlugin::ConstructL() - exit"));
    }

CPwrPlugin::~CPwrPlugin()
    {
    LOGTEXT(_L("CPwrPlugin::~CPwrPlugin() - entry"));
    if(iPowerListener)
        {
        if(Enabled())
            {
            iPowerListener->Stop();
            }
        delete iPowerListener;
        iPowerListener = NULL;
        }

    if(iSamplerAttributes)
        {
        iSamplerAttributes->Reset();
        delete iSamplerAttributes;
        iSamplerAttributes = NULL;
        }

    LOGTEXT(_L("CPwrPlugin::~CPwrPlugin() - exit"));
    }

TUid CPwrPlugin::Id(TInt /*aSubId*/) const
    {
    LOGSTRING2( "CPwrPlugin::Id():0x%X", KSamplerPwrPluginUid.iUid );
    return KSamplerPwrPluginUid;
    }

void CPwrPlugin::InitiateSamplerAttributesL()
    {
    // create TSamplerAttributes
    TSamplerAttributes attr(KSamplerPwrPluginUid.iUid,
            KPWRShortName(),
            KPWRLongName(),
            KPWRDescription(),
            250,
            EFalse,
            EFalse,
            0); 
    this->iSamplerAttributes->AppendL(attr);
    }

void CPwrPlugin::SetEnabled(TBool aEnabled)
    {
    iEnabled = aEnabled;
    }

// returns setting array
void CPwrPlugin::GetAttributesL(CArrayFixFlat<TSamplerAttributes>* aAttributes)
    {
    aAttributes->AppendL(iSamplerAttributes->At(0));
    }

TInt CPwrPlugin::SetAttributesL(TSamplerAttributes aAttributes)
    {
    TSamplerAttributes attr;

    attr = iSamplerAttributes->At(0);
    // replace the old attribute container
    iSamplerAttributes->Delete(0);
    iSamplerAttributes->InsertL(0, aAttributes);
    return KErrNone;
    }

/* 
 * Method for parsing and transforming text array settings into TSamplerAttributes (per each sub sampler),
 * called by CSamplerController class
 * 
 * @param array of raw text setting lines, e.g. [gpp]\nenabled=true\nsampling_period_ms=1\n
 */
TInt CPwrPlugin::ConvertRawSettingsToAttributes(CDesC8ArrayFlat* aAllSettingsArray)
    {
    // local literals
    _LIT8(KPWRShort, "pwr");

    TInt err(KErrNone);
    TBuf8<16> samplerSearchName;
    samplerSearchName.Copy(KPWRShort);

    // get sampler specific settings  
    err = DoSetSamplerSettings(aAllSettingsArray, samplerSearchName, 0);

    // returns KErrNone if settings found, otherwise KErrNotFound
    return err;
    }

TInt CPwrPlugin::DoSetSamplerSettings(CDesC8ArrayFlat* aAllSettings, TDesC8& aSamplerName, TInt aIndex)
    {
    // 
    TBuf8<16> samplerSearch;
    samplerSearch.Copy(KBracketOpen);
    samplerSearch.Append(aSamplerName);
    samplerSearch.Append(KBracketClose);

    // read a line
    for (TInt i(0); i<aAllSettings->MdcaCount(); i++)
        {
        // check if this line has a setting block start, i.e. contains [xxx] in it
        if (aAllSettings->MdcaPoint(i).CompareF(samplerSearch) == 0)
            {
            // right settings block found, now loop until the next block is found
            for(TInt j(i+1);j<aAllSettings->MdcaCount();j++)
                {
                // check if the next settings block was found
                if(aAllSettings->MdcaPoint(j).Left(1).CompareF(KBracketOpen) != 0)
                    {
                    // save found setting value directly to its owners attributes
                    SaveSettingToAttributes(aAllSettings->MdcaPoint(j), aIndex);
                    }
                else
                    {
                    // next block found, return KErrNone
                    return KErrNone;
                    }
                }
            }
        }

    return KErrNotFound;
    }

/**
 * Method for setting a specific descriptor (from settings file) to attribute structure
 * 
 * @param aSetting  
 * @param aName  
 */
void CPwrPlugin::SaveSettingToAttributes(const TDesC8& aSetting, TInt aIndex)
    {
    // find the equal mark from the setting line
    TInt sepPos = aSetting.Find(KSettingItemSeparator);
    // check that '=' is found
    if (sepPos > 0)
        {
        // check that the element matches
        if (aSetting.Left(sepPos).CompareF(KEnabled) == 0)
            {
            TBool en;
            CSamplerPluginInterface::Str2Bool(aSetting.Right(aSetting.Length()-sepPos-1), en);
            if(en != iSamplerAttributes->At(aIndex).iEnabled)
                {
                iSamplerAttributes->At(aIndex).iEnabled = en;
                }
            }
        else if (aSetting.Left(sepPos).CompareF(KSamplingPeriodMs) == 0)
            {
            TInt sr;
            CSamplerPluginInterface::Str2Int(aSetting.Right(aSetting.Length()-sepPos-1), sr);
            if(sr != iSamplerAttributes->At(aIndex).iSampleRate)
                {
                iSamplerAttributes->At(aIndex).iSampleRate = sr;
                }
            }
        }
    }

TInt CPwrPlugin::GetSamplerType()
    {
    return iSamplerType;
    }

TInt CPwrPlugin::ResetAndActivateL(CProfilerSampleStream& aStream) 
    {
    LOGTEXT(_L("CPwrPlugin::ResetAndActivate() - entry"));
    // check if sampler enabled
    if(iSamplerAttributes->At(0).iEnabled)
        {
        // create a new listener instance for every trace, destroy it on stop
        iPowerListener = CProfilerPowerListener::NewL(this);

        iStream = &aStream;
        TInt length = this->CreateFirstSample();
        iVersion[0] = (TUint8)length;
        LOGSTRING2("CPwrPlugin::ResetAndActivate() - AddSample, length %d", length);
        TInt ret = this->AddSample(iVersion, length+1, 0);

        LOGSTRING2("CPwrPlugin::ConstructL() - sampling period %d", this->iPeriod);

        HBufC8* iBufRes = HBufC8::NewMaxLC(10);
        TPtr8 iPtrRes = iBufRes->Des();

        // check if sampling rate set to something reasonable, relevant only in SYNC case
        if(iSamplerAttributes->At(0).iSampleRate != -1)
            {
            iPtrRes.Num(iSamplerAttributes->At(0).iSampleRate);
            }
        else
            {
            iPtrRes.Append(KNullDesC8);
            }

        // set disabled
        SetEnabled(ETrue); 

        // activate power listener
        ret = iPowerListener->StartL(iPtrRes);
        LOGTEXT(_L("CPwrPlugin::ResetAndActivate() - exit"));

        CleanupStack::PopAndDestroy();
        
        if(ret != KErrNone)
            return ret;
        }
    return KErrNone;
    }

TInt CPwrPlugin::CreateFirstSample() 
    {
    LOGTEXT(_L("CPwrPlugin::CreateFirstSample - entry"));
    this->iVersionDescriptor.Zero();
    this->iVersionDescriptor.Append(_L8("Bappea_PWR_V"));
    this->iVersionDescriptor.Append(PROFILER_PWR_SAMPLER_VERSION);
    LOGTEXT(_L("CPwrPlugin::CreateFirstSample - exit"));
    return (TInt)(this->iVersionDescriptor.Length());
    }

TInt CPwrPlugin::StopSampling() 
    {
    if(iPowerListener)
        {
        iPowerListener->Stop();
        delete iPowerListener;
        iPowerListener = NULL;
        }

    // set disabled
    SetEnabled(EFalse);

    return KErrNone;
    }


/*
 *
 * class CProfilerPowerListener implementation
 * 
 */

CProfilerPowerListener::CProfilerPowerListener(CPwrPlugin* aSampler) :
    iPwrSamplingPeriod(0),
    iOriginalReportingPeriod(0),
    iNominalCapa(0),
    iVoltage(0), 
    iCurrent(0),
    iPowerAPI(0)
#ifdef PWR_SAMPLER_BACKLIGHT
    ,iLightAPI(0),
    iBackLightStatus(CHWRMLight::ELightStatusUnknown)
#endif

    {
    LOGTEXT(_L("CProfilerPowerListener::CProfilerPowerListener() - konstuktori"));
    this->iSampler = aSampler;
    LOGTEXT(_L("CProfilerPowerListener::CProfilerPowerListener() - konstuktori exit"));
    }

CProfilerPowerListener* CProfilerPowerListener::NewL(CPwrPlugin* aSampler)
    {
    LOGTEXT(_L("CProfilerPowerListener::NewL() - entry"));
    CProfilerPowerListener* self = new (ELeave) CProfilerPowerListener(aSampler);
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop();
    LOGTEXT(_L("CProfilerPowerListener::NewL() - exit"));
    return self;
    }

void CProfilerPowerListener::ConstructL()
    {
    LOGTEXT(_L("CProfilerPowerListener::ConstructL() - entry"));
    iSampleStartTime = 0;
    LOGTEXT(_L("CProfilerPowerListener::ConstructL() - exit"));
    }

CProfilerPowerListener::~CProfilerPowerListener() 
    {
    LOGTEXT(_L("CProfilerPowerListener::~CProfilerPowerListener() - entry"));

    if (iPowerAPI)
        {
        delete iPowerAPI;
        iPowerAPI = 0;
        }
#ifdef PWR_SAMPLER_BACKLIGHT
    if (iLightAPI)
        {
        delete iLightAPI;
        iLightAPI = 0;
        }
#endif

    LOGTEXT(_L("CProfilerPowerListener::~CProfilerPowerListener() - exit"));
    }

TInt CProfilerPowerListener::DisplayNotifierL(const TDesC& aLine1, const TDesC& aLine2, const TDesC& aButton1, const TDesC& aButton2)
    {
    RNotifier notifier;
    TRequestStatus stat;

    TInt buttonValue(0);

    User::LeaveIfError(notifier.Connect());

    notifier.Notify(aLine1, aLine2, aButton1, aButton2, buttonValue, stat);
    User::WaitForRequest(stat);

    notifier.Close();
    return buttonValue;
    }


TInt CProfilerPowerListener::StartL(const TDesC8& aBuf)
    {
    LOGTEXT(_L("CProfilerPowerListener::StartL() - entry"));

    // get the property value
    TInt r = RProperty::Get(KGppPropertyCat, EGppPropertySyncSampleNumber, iSampleStartTime);
    if(r != KErrNone)
        {
        LOGSTRING2("CProfilerPowerListener::StartL() - getting iSyncOffset failed, error %d", r);
        }

   // check if given sampling period is valid
    if(aBuf.CompareF(KNullDesC8)!= 0)
        {
        TLex8* lex = new TLex8(aBuf);
        lex->Val(iPwrSamplingPeriod);
        delete lex;
        }
    else
        {
        // set default period
        iPwrSamplingPeriod = 250;
        }

    // Check that sampling period is in allowed range
    if (KMinSampleInterval > 0 && iPwrSamplingPeriod < KMinSampleInterval)
        {
        iPwrSamplingPeriod = KMinSampleInterval;
        }

    LOGSTRING2("CProfilerPowerListener::StartL() - Sampling period %d", iPwrSamplingPeriod);

    // Start monitoring voltage and current
    iPowerAPI = CHWRMPower::NewL();
    iPowerAPI->SetPowerReportObserver(this);

    // Read HWRM reporting settings from central repository
    CRepository* centRep = CRepository::NewL(KCRUidPowerSettings);
    TInt baseInterval(0);
    User::LeaveIfError(centRep->Get(KPowerBaseTimeInterval, baseInterval));
    User::LeaveIfError(centRep->Get(KPowerMaxReportingPeriod, iOriginalReportingPeriod));

    LOGSTRING2("CProfilerPowerListener::StartL() - HWRM base power report interval: %d", baseInterval);
    LOGSTRING2("CProfilerPowerListener::StartL() - Original HWRM max power reporting period: %d", iOriginalReportingPeriod);

    User::LeaveIfError(centRep->Set(KPowerMaxReportingPeriod, KReportingPeriodInfinite));

    // Power reporting interval reading may return too low value sometimes. Minimum value expected to be 250ms.
    if ( baseInterval < KMinSampleInterval )
        {
        baseInterval = KMinSampleInterval;
        LOGSTRING2("CProfilerPowerListener::StartL() - Power report interval too low. Changed to: %d", baseInterval);
        }

    // Power reporting period is multiplier of HWRM base period
    TInt intervalMultiplier = iPwrSamplingPeriod / baseInterval;

    if (intervalMultiplier < 1)
        {
        intervalMultiplier = 1;
        }

    LOGSTRING2("CProfilerPowerListener::StartL() - Reporting period multiplier: %d", intervalMultiplier);

    TRequestStatus status(KRequestPending);
    iPowerAPI->StartAveragePowerReporting(status, intervalMultiplier);
    User::WaitForRequest(status);

    if (status.Int() != KErrNone)
        {
        LOGTEXT(_L("CProfilerPowerListener::StartL() - Failed to initialize power reporting"));

        DisplayNotifierL(KPowerTextLine1, KPowerTextLine2, KButtonOk, KNullDesC);

        return status.Int();
        }

#ifdef PWR_SAMPLER_BACKLIGHT
    // Start monitoring backlight status
    iLightAPI = CHWRMLight::NewL(this);
#endif

    LOGTEXT(_L("CProfilerPowerListener::StartL() - exit"));
    return KErrNone;
    }

void CProfilerPowerListener::Sample()
    {
    LOGTEXT(_L("CProfilerPowerListener::Sample() - entry"));

    TRequestStatus status;
    CHWRMPower::TBatteryConsumptionData consumptionData;

    iPowerAPI->GetBatteryInfo(status, consumptionData);
    User::WaitForRequest(status);

    // Data is valid only if status == KErrNone 
    if (status.Int() != KErrNone)
        {
        LOGSTRING2("CProfilerPowerListener::Sample() - Getting battery info failed with code: ", status.Int());
        iNominalCapa = 0;
        }
    else
        {
        iNominalCapa = consumptionData.iNominalCapacity;
        }

    // Space for GPP sample time        
    //TUint32 sampleTime = iSampler->iStream->iSampler->GetSampleTime();
    TUint32 sampleTime = User::NTickCount() - iSampleStartTime;
    LOGSTRING2("CProfilerPowerListener::Sample() - Sample time: %d", sampleTime);
    LOGSTRING2("CProfilerPowerListener::Sample() - Nominal capacitance: %d", iNominalCapa);
    LOGSTRING2("CProfilerPowerListener::Sample() - Voltage: %d", iVoltage);
    LOGSTRING2("CProfilerPowerListener::Sample() - Current: %d", iCurrent);
#ifdef PWR_SAMPLER_BACKLIGHT
    LOGSTRING2("CProfilerPowerListener::Sample() - Backlight status: %d", (TUint8)iBackLightStatus);
#endif

    iSample[0] = iNominalCapa;
    iSample[1] = iNominalCapa >> 8;
    iSample[2] = iVoltage;
    iSample[3] = iVoltage >> 8;
    iSample[4] = iCurrent;
    iSample[5] = iCurrent >> 8;
    iSample[6] = iCurrent >> 16;
    iSample[7] = iCurrent >> 24;
#ifdef PWR_SAMPLER_BACKLIGHT
    iSample[8] = (TUint8)iBackLightStatus;
    iSample[9] = sampleTime;
    iSample[10] = sampleTime >> 8;
    iSample[11] = sampleTime >> 16;
    iSample[12] = sampleTime >> 24;

    iSampler->AddSample(iSample, 13, 0);
#else
    iSample[8] = sampleTime;
    iSample[9] = sampleTime >> 8;
    iSample[10] = sampleTime >> 16;
    iSample[11] = sampleTime >> 24;

    iSampler->AddSample(iSample, 12, 0);
#endif

    LOGTEXT(_L("CProfilerPowerListener::Sample() - exit"));
    }

TInt CProfilerPowerListener::Stop() 
    {
    LOGTEXT(_L("CProfilerPowerListener::Stop() - entry"));

    if (iPowerAPI)
        {
        TRAPD(err, iPowerAPI->StopAveragePowerReportingL());
        if(err != KErrNone)
            {
            LOGSTRING2("CProfilerPowerListener::Stop() - Failed to stop power reporting: %d", err);
            }
        else
            {
            LOGTEXT(_L("CProfilerPowerListener::Stop() - Stopped power monitoring"));
            }
        delete iPowerAPI;
        iPowerAPI = 0;

        // Restore original value to max sampling period
        CRepository* centRep = 0;
        TRAP(err, centRep = CRepository::NewL(KCRUidPowerSettings));
        if (err != KErrNone)
            {
            LOGSTRING2("CProfilerPowerListener::Stop() - Failed to open Central Repository: %d", err);
            }
        else
            {
            err = centRep->Set(KPowerMaxReportingPeriod, iOriginalReportingPeriod);
            if(err != KErrNone)
                {
                LOGSTRING2("CProfilerPowerListener::Stop() - Failed to restore max sampling period: %d", err);
                }
            }
        }
#ifdef PWR_SAMPLER_BACKLIGHT
    if (iLightAPI)
        {
        delete iLightAPI;
        iLightAPI = 0;
        }
#endif

    LOGTEXT(_L("CProfilerPowerListener::Stop() - exit"));
    return KErrNone;
    }

void CProfilerPowerListener::PowerMeasurement(TInt aErr, CHWRMPower::TBatteryPowerMeasurementData& aMeasurement)
    {
    LOGTEXT(_L("CProfilerPowerListener::PowerMeasurement - entry"));

    if (aErr == KErrNone)
        {
        LOGSTRING3("CProfilerPowerListener::PowerMeasurement - Previous values - Voltage: %d Current: %d", iVoltage, iCurrent);
        iVoltage = aMeasurement.iAverageVoltage;
        iCurrent = aMeasurement.iAverageCurrent;
        LOGSTRING3("CProfilerPowerListener::PowerMeasurement - New values - Voltage: %d Current: %d", iVoltage, iCurrent);

        this->Sample();
        }
    else
        {
        LOGSTRING2("CProfilerPowerListener::PowerMeasurement - Failed with error code: %d", aErr);
        DisplayNotifierL(KPowerTextLine1, KPowerTextErrorSampling, KButtonOk, KNullDesC);
        }
    LOGTEXT(_L("CProfilerPowerListener::PowerMeasurement - exit"));
    }

#ifdef PWR_SAMPLER_BACKLIGHT
void CProfilerPowerListener::LightStatusChanged(TInt aTarget, CHWRMLight::TLightStatus aStatus)
    {
    LOGTEXT(_L("CProfilerPowerListener::LightStatusChanged - entry"));
    LOGSTRING3("CProfilerPowerListener::LightStatusChanged - Target: %d Status: %d", aTarget, aStatus);

    if (aTarget == CHWRMLight::EPrimaryDisplay)
        {
        LOGSTRING2("CProfilerPowerListener::LightStatusChanged - Previous light status: %d", iBackLightStatus);
        iBackLightStatus = aStatus;
        LOGSTRING2("CProfilerPowerListener::LightStatusChanged - New light status: %d", iBackLightStatus);

        this->Sample();
        }
    LOGTEXT(_L("CProfilerPowerListener::LightStatusChanged - exit"));
    }
#endif