// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Symbian Foundation License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// @file T_Lbschannel.cpp
// This is the Cpp file which contains the channel for communication between
// the test harness and the test AGps module.
//
//
// User includes
#include "tlbschannel.h"
const TInt KLbsChannelIdMax = RT_LbsChannel::EChannelTAGPS2TH;
//const TInt KCategoryKeyIndex = 0;
const TInt KReadPropKeyIndex = 1;
const TInt KReadPropAckKeyIndex = 2;
const TInt KWritePropKeyIndex = 3;
const TInt KWritePropAckKeyIndex = 4;
/** The array contains description (property size, keys and Ids) of all the channels supported by
the RT_LbsChannel interface */
const TUint KPropTable[KLbsChannelIdMax+1][5]=
{
{0, KTH2TAGPSMessageKey, KTH2TAGPSMessageReadAckKey, KTAGPS2THMessageKey, KTAGPS2THMessageReadAckKey},
{0, KTAGPS2THMessageKey, KTAGPS2THMessageReadAckKey, KTH2TAGPSMessageKey, KTH2TAGPSMessageReadAckKey},
};
///////////////////////////////////////////////////////////////////////////////
// RT_LbsChannel
///////////////////////////////////////////////////////////////////////////////
EXPORT_C void RT_LbsChannel::InitializeL(TT_LbsChannelId aChannelId)
{
const TSecurityPolicy KReadPolicy(ECapability_None);
const TSecurityPolicy KWritePolicy(ECapabilityWriteDeviceData);
TInt err = RProperty::Define(KUidSystemCategory,
KPropTable[aChannelId][KWritePropKeyIndex],
RProperty::ELargeByteArray,
KReadPolicy, KWritePolicy,
sizeof(TT_LbsMsgBase));
if (err != KErrNone && err != KErrAlreadyExists)
{
User::Leave(err);
}
err = RProperty::Define(KUidSystemCategory,
KPropTable[aChannelId][KWritePropAckKeyIndex],
RProperty::EInt,
KReadPolicy, KWritePolicy);
if (err != KErrNone && err != KErrAlreadyExists)
{
User::Leave(err);
}
User::LeaveIfError(RProperty::Set(KUidSystemCategory, KPropTable[aChannelId][KWritePropAckKeyIndex], 0));
}
EXPORT_C void RT_LbsChannel::ShutDownL(TT_LbsChannelId aChannelId)
{
User::LeaveIfError(RProperty::Delete(KPropTable[aChannelId][KWritePropKeyIndex]));
User::LeaveIfError(RProperty::Delete(KPropTable[aChannelId][KWritePropAckKeyIndex]));
}
EXPORT_C RT_LbsChannel::RT_LbsChannel()
{
}
/**
The channel must first be initialised before this is called, otherwise the
resources needed by the channel will not have been allocated.
@param aObserver Reference to the observer class used to notify of new messages.
@param aChannelId Uid of the RProperty category used for this channel.
@leave
*/
EXPORT_C void RT_LbsChannel::OpenL(TT_LbsChannelId aChannelId, MT_LbsChannelObserver& aObserver)
{
__ASSERT_DEBUG(iSendProperty.Handle()==NULL, User::Invariant());
__ASSERT_DEBUG(iSendMsgReadProperty.Handle()==NULL, User::Invariant());
User::LeaveIfError(iSendProperty.Attach(KUidSystemCategory, KPropTable[aChannelId][KWritePropKeyIndex]));
User::LeaveIfError(iSendMsgReadProperty.Attach(KUidSystemCategory, KPropTable[aChannelId][KWritePropAckKeyIndex]));
iMonitor = CT_ChannelMonitor::NewL(aObserver, aChannelId, KUidSystemCategory,
KPropTable[aChannelId][KReadPropKeyIndex],
KPropTable[aChannelId][KReadPropAckKeyIndex]);
}
/** Close the connection.
This function closes the connection and frees any resources
created in RTbsChannel::OpenL().
*/
EXPORT_C void RT_LbsChannel::Close()
{
CancelSendMessageNotification();
delete iMonitor;
iSendProperty.Close();
iSendMsgReadProperty.Close();
}
/** Send a message through the channel.
This is an asynchronous function that only completes when the message
has been read.
If another call is made to this function before a previous one has
completed then aStatus will be completed straight away, with the
completion code KErrInUse.
@param aMessage The message to be sent.
@param aStatus Request status that is completed when the message has
been read. If there is an error sending the message
it will be stored in aStatus.Int().
*/
EXPORT_C void RT_LbsChannel::SendMessage(const TT_LbsMsgBase& aMessage,
TRequestStatus& aStatus)
{
// Must check that the previous message was read
TInt sendAck;
iSendMsgReadProperty.Get(sendAck);
if (sendAck == 1)
{
// Pending message has not been read yet; flag an error
TRequestStatus* statPtr = &aStatus;
User::RequestComplete(statPtr, KErrInUse);
}
else
{
// Publish the new message
iSendMsgReadProperty.Set(1);
iSendMsgReadProperty.Subscribe(aStatus);
TPckgC<TT_LbsMsgBase> pckg(aMessage);
iSendProperty.Set(pckg);
}
}
/** Cancel the current request status for SendMessage().
*/
EXPORT_C void RT_LbsChannel::CancelSendMessageNotification()
{
iSendMsgReadProperty.Cancel();
}
///////////////////////////////////////////////////////////////////////////////
// CT_ChannelMonitor - used to listen for incoming messages
///////////////////////////////////////////////////////////////////////////////
CT_ChannelMonitor* CT_ChannelMonitor::NewL(MT_LbsChannelObserver& aObserver, RT_LbsChannel::TT_LbsChannelId aChannelId, TUid aPropId, TUint aPropKey, TUint aAckPropKey)
{
CT_ChannelMonitor* self = new (ELeave) CT_ChannelMonitor(aObserver, aChannelId);
CleanupStack::PushL(self);
self->ConstructL(aPropId, aPropKey, aAckPropKey);
CleanupStack::Pop();
return self;
}
CT_ChannelMonitor::CT_ChannelMonitor(MT_LbsChannelObserver& aObserver, RT_LbsChannel::TT_LbsChannelId aChannelId) :
CActive(EPriorityStandard),
iObserver(aObserver),
iChannelId(aChannelId)
{
CActiveScheduler::Add(this);
}
CT_ChannelMonitor::~CT_ChannelMonitor()
{
Cancel();
iReceiveProperty.Close();
iReceiveMsgReadProperty.Close();
}
void CT_ChannelMonitor::ConstructL(TUid aPropId, TUint aPropKey, TUint aAckPropKey)
{
__ASSERT_DEBUG(iReceiveProperty.Handle()==NULL, User::Invariant()); //Handle open.
__ASSERT_DEBUG(iReceiveMsgReadProperty.Handle()==NULL, User::Invariant()); //Handle open.
User::LeaveIfError(iReceiveProperty.Attach(aPropId, aPropKey));
User::LeaveIfError(iReceiveMsgReadProperty.Attach(aPropId, aAckPropKey));
NotifyChannelMessage();
// flag we are ready for receiving messages
iReceiveMsgReadProperty.Set(0);
}
void CT_ChannelMonitor::NotifyChannelMessage()
{
iReceiveProperty.Subscribe(iStatus);
SetActive();
}
void CT_ChannelMonitor::RunL()
{
TInt result = iStatus.Int();
switch (result)
{
case KErrNone:
{
// Read property
TT_LbsMsgBase msg;
TPckg<TT_LbsMsgBase> pckg(msg);
iReceiveProperty.Get(pckg);
// resubscribe for further messages
NotifyChannelMessage();
// Notify observer
iObserver.ProcessChannelMessage(iChannelId, msg);
// flag message as read
iReceiveMsgReadProperty.Set(0);
break;
}
default:
{
User::Leave(result);
break;
}
}
}
void CT_ChannelMonitor::DoCancel()
{
iReceiveProperty.Cancel();
}
TInt CT_ChannelMonitor::RunError(TInt /*aError*/)
{
return KErrNone;
}