sensorservices/sensorserver/src/server/sensrvchannelbuffer.cpp
changeset 0 4e1aa6a622a0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sensorservices/sensorserver/src/server/sensrvchannelbuffer.cpp	Tue Feb 02 00:53:00 2010 +0200
@@ -0,0 +1,694 @@
+/*
+* Copyright (c) 2006-2008 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:  Sensor server channel buffer implementation
+*
+*/
+
+
+#include "sensrvdefines.h"
+#include "sensrvchannel.h"
+#include "sensrvpluginproxy.h"
+#include "sensrvchannelbuffer.h"
+#include "sensrvchannellistener.h"
+
+
+// ---------------------------------------------------------------------------
+// 2-phase constructor
+// ---------------------------------------------------------------------------
+//
+CSensrvChannelBuffer* CSensrvChannelBuffer::NewL(TInt aItemSize,
+                                                 TInt aBufferLength)
+    {
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::NewL(aItemSize: %d, aBufferLength: %d)" ), aItemSize, aBufferLength ) );
+
+    CSensrvChannelBuffer* self = new( ELeave ) CSensrvChannelBuffer(aItemSize, aBufferLength);
+    
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::NewL - return 0x%x" ), self ) );
+
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// C++ constructor
+// ---------------------------------------------------------------------------
+//
+CSensrvChannelBuffer::CSensrvChannelBuffer(TInt aItemSize,
+                                           TInt aBufferLength)
+    : iItemSize(aItemSize),
+      iBufferLength(aBufferLength < KSensrvMinimumBufferLength ? KSensrvMinimumBufferLength : aBufferLength),
+      iLatestWrittenItemIndex( KErrNotFound )
+    {
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::CSensrvChannelBuffer()" )) );
+
+    // Nothing to do
+
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::CSensrvChannelBuffer - return" ) ) );
+    }
+
+// ---------------------------------------------------------------------------
+// 2nd phase of construction
+// ---------------------------------------------------------------------------
+//
+void CSensrvChannelBuffer::ConstructL()
+    {
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::ConstructL()" ) ) );
+
+    // Check parameter validity here, as constructor cannot leave.
+    TInt bufferSize = iItemSize*iBufferLength;
+    if (   iItemSize <= 0 
+        || iBufferLength <= 0 
+        || (KMaxTInt/iItemSize) <= iBufferLength )
+        {
+        ERROR_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::ConstructL - ERROR: Invalid parameters" ) ) );
+        User::Leave(KErrArgument);
+        }
+
+    // Construct buffer
+    iBuffer = HBufC8::NewL(bufferSize);
+
+    BUFFER_TRACE( ( _L( "#### CSensrvChannelBuffer::ConstructL(): iBufferLength: %d" ), iBufferLength ) );
+
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::ConstructL - return" ) ) );
+    }
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CSensrvChannelBuffer::~CSensrvChannelBuffer()
+    {
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::~CSensrvChannelBuffer()" ) ) );
+
+    delete iBuffer;
+    
+    iTailIndexArray.ResetAndDestroy();
+
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::~CSensrvChannelBuffer - return" ) ) );
+    }
+
+// ---------------------------------------------------------------------------
+// Get pointer to next free block (the beginning of head index item)
+// Invalidate next aCount items and move indexes accordingly.
+// ---------------------------------------------------------------------------
+//
+TUint8* CSensrvChannelBuffer::GetFreeBlock(TInt aCount)
+    {
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::GetFreeBlock(aCount: %d)" ), aCount ) );
+
+    __ASSERT_ALWAYS(aCount <= iBufferLength, User::Panic(KSensrvPanicCategory, ESensrvPanicOutOfBounds));
+    __ASSERT_ALWAYS(!iRequestedFreeBlockLength, User::Panic(KSensrvPanicCategory, ESensrvPanicPreviousBlockNotYetWritten));
+
+    // Check if there is enough space in the end of the buffer to allocate continuous
+    // block of aCount items
+    if (iHeadIndex + aCount > iBufferLength)
+        {
+        // No room, invalidate the end of buffer and move head to start of buffer.
+        InvalidateRange(iBufferLength);
+        iHeadIndex = 0;
+        }
+    else
+        {
+        // There is room at end of buffer, do nothing
+        }
+    
+    // Invalidate desired range
+    InvalidateRange(aCount);
+
+    // Get head pointer
+    TUint8* ptr = const_cast<TUint8*>(iBuffer->Ptr());
+    ptr += iHeadIndex*iItemSize;
+    
+    iRequestedFreeBlockLength = aCount;
+    
+    DEBUG_PRINT_BUFFER;
+
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::GetFreeBlock - return %d" ), ptr ) );
+    
+    return ptr;
+    }
+
+// ---------------------------------------------------------------------------
+// Validate specified count of items and adjust indexes.
+// Head index is moved aCount items forward, as well as iValidEndIndex,
+// if that is at head.
+// ---------------------------------------------------------------------------
+//
+void CSensrvChannelBuffer::WroteBlock(TInt aCount)
+    {
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::WroteBlock(aCount: %d)" ), aCount ) );
+
+    __ASSERT_ALWAYS(iRequestedFreeBlockLength >= aCount, User::Panic(KSensrvPanicCategory, ESensrvPanicRequestedFreeBlockTooSmall));
+
+    // Negative count indicates an error
+    TInt total(iHeadIndex + aCount);
+    
+    if (aCount < 0 || total > iBufferLength)
+        {
+        ERROR_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::WroteBlock - Invalid count: %d, iBufferLength: %d, iHeadIndex: %d" ), aCount, iBufferLength, iHeadIndex ) );
+        }
+    else if (aCount)
+        {
+        // Store the latest written item index to be used as initial data
+        iLatestWrittenItemIndex = total - 1;
+        
+        iHeadIndex = total;
+
+        if (iValidEndIndex < iHeadIndex)
+            {
+            iValidEndIndex = iHeadIndex;
+            }
+            
+        if (iHeadIndex == iBufferLength)    
+            {
+            iHeadIndex = 0;
+            }
+        
+        for(TInt i = 0; i < iTailIndexArray.Count(); i++)
+            {
+            UpdateDataAvailable(*(iTailIndexArray[i]), ETrue);
+            }
+        }
+    else
+        {
+        // Nothing to do when count is zero
+        }
+
+    iRequestedFreeBlockLength = 0;
+
+    DEBUG_PRINT_BUFFER;
+    }
+
+// ---------------------------------------------------------------------------
+// Cancels any outstanding free block request
+// ---------------------------------------------------------------------------
+//
+void CSensrvChannelBuffer::CancelFreeBlock()
+    {
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::CancelFreeBlock()" ) ) );
+
+    iRequestedFreeBlockLength = 0;
+
+    DEBUG_PRINT_BUFFER;
+
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::CancelFreeBlock - return" ) ) );
+    }
+
+// ---------------------------------------------------------------------------
+// Adds a listener tail index
+// ---------------------------------------------------------------------------
+//
+TInt CSensrvChannelBuffer::AddListener(CSensrvChannelListener* aListener,
+                                       TSensrvTailIndexItem*& aTailItem,
+                                       CSensrvChannelListener::TSensrvChannelListenerState aState)
+    {
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::AddListener(aListener: 0x%x, <retval>, aState: %d)" ), aListener, aState ) );
+
+    __ASSERT_ALWAYS(aListener, User::Panic(KSensrvPanicCategory, ESensrvPanicNullListener));
+    __ASSERT_ALWAYS(GetTailIndex(aListener) == KErrNotFound, User::Panic(KSensrvPanicCategory, ESensrvPanicDuplicateListener));
+    
+    aTailItem = new TSensrvTailIndexItem(aListener);
+
+    TInt err(KErrNoMemory);
+
+    if (aTailItem)
+        {
+        if (aState == CSensrvChannelListener::EChannelListenerStateDataListening)
+            {
+            // If no outstanding request for data block (i.e. first listener),
+            // initialize index to head index.
+            if (iRequestedFreeBlockLength)
+                {
+                aTailItem->iDataTailIndex = KSensrvChannelBufferUninitializedTail;
+                }
+            else
+                {
+                aTailItem->iDataTailIndex = iHeadIndex;
+                }
+            }
+        else if (aState == CSensrvChannelListener::EChannelListenerStateConditionListening)
+            {
+            // Unlike data, conditions are available immediately, regardless of 
+            // current listening state. Each condition set will individually
+            // be evaluated if it should ignore new data.
+            aTailItem->iConditionTailIndex = iHeadIndex;
+            }
+        else
+            {
+            ERROR_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::AddListener - ERROR: Invalid state: %d" ), aState ) );
+            }
+
+
+        err = iTailIndexArray.Append(aTailItem);
+        
+        if (err != KErrNone)
+            {
+            delete aTailItem;
+            aTailItem = NULL;
+            }
+        }
+
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::AddListener - return %d, aTailItem: 0x%x" ), err, aTailItem ) );
+   
+    return err;
+    }
+
+// ---------------------------------------------------------------------------
+// Removes a listener tail index
+// ---------------------------------------------------------------------------
+//
+void CSensrvChannelBuffer::RemoveListener(CSensrvChannelListener* aListener)
+    {
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::DeleteListener(aListener: 0x%x)" ), aListener ) );
+
+    __ASSERT_ALWAYS(aListener, User::Panic(KSensrvPanicCategory, ESensrvPanicNullListener));
+    TBool removed(EFalse);
+
+    for(TInt i = 0; !removed && i < iTailIndexArray.Count(); i++)
+        {
+        if (iTailIndexArray[i]->iListener == aListener)
+            {
+            delete iTailIndexArray[i];
+            iTailIndexArray.Remove(i);
+            removed = ETrue;
+            }
+        }
+    
+    // Clear requested free block length    
+    if( iTailIndexArray.Count() == 0 )
+        {
+        CancelFreeBlock();
+        }
+
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::DeleteListener - return (removed: %d)" ), removed ) );
+    }
+
+// ---------------------------------------------------------------------------
+// Get new data for listener to transaction data item
+// ---------------------------------------------------------------------------
+//
+void CSensrvChannelBuffer::GetMessageData(TSensrvTailIndexItem* aTailItem,
+                                          CSensrvChannelListener::TChannelDataMessage& aMessageData,
+                                          TInt aCount)
+    {
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::GetMessageData(aCount: %d)" ), aCount ) );
+    
+    if( aTailItem == NULL )
+        return;
+    
+    TBool done(EFalse);
+    TInt actualCount(aCount > aTailItem->iDataAvailable ? aTailItem->iDataAvailable : aCount);
+
+    // Get tail item pointer
+    TUint8* startPtr = const_cast<TUint8*>(iBuffer->Ptr());
+    TUint8* tailPtr = startPtr + aTailItem->iDataTailIndex*iItemSize;
+
+    TPtrC8* activePart = &aMessageData.iFirstDataPart;
+
+    aMessageData.iDataLostCount = aTailItem->iDataLostCount;
+    
+    while (!done)
+        {
+        TInt available(0);
+
+        // Adjust tail index
+        if (!aTailItem->iDataAvailable)
+            {
+            // No new data available, do nothing
+            BUFFER_TRACE((_L("#### No more data available")));
+            done = ETrue;
+            }
+        else if ( aTailItem->iDataTailIndex < iHeadIndex )
+            {
+            // Data available up to head index
+            available = iHeadIndex - aTailItem->iDataTailIndex;
+            TInt remainder = actualCount - aMessageData.iDataItemCount;
+            if (remainder < available)
+                {
+                available = remainder;
+                }
+            BUFFER_TRACE((_L("#### More data was available")));
+            done = ETrue;
+            }
+        else // iTailIndexArray[index].iDataTailIndex >= iHeadIndex
+            {
+            // New data available up to iValidEndIndex and possibly more again from start
+            // Only possible to get here on first pass.
+            available  = iValidEndIndex - aTailItem->iDataTailIndex;
+            if (actualCount <= available)
+                {
+                available = actualCount;
+                done = ETrue; // No second pass needed
+                BUFFER_TRACE((_L("#### Just single block of data was available")));
+                }
+            else
+                {
+                BUFFER_TRACE((_L("#### Possibly second block of data available")));
+                }
+            } 
+
+        aTailItem->iDataTailIndex += available;
+        activePart->Set(tailPtr, available*iItemSize);
+        aMessageData.iDataItemCount += available;
+        
+        // Roll tail index over to zero if at end of buffer,
+        // unless valid buffer ends at head index, in which case
+        // SSY has reserved a block beginning from iValidEndIndex,
+        // and we should wait for new data at current index.
+        if (aTailItem->iDataTailIndex == iValidEndIndex && iValidEndIndex != iHeadIndex)
+            {
+            aTailItem->iDataTailIndex = 0;
+            tailPtr = startPtr;
+            activePart = &aMessageData.iSecondDataPart;
+            }
+
+        UpdateDataAvailable(*aTailItem, EFalse);
+        }
+
+    aTailItem->iDataLostCount = 0;
+    
+    DEBUG_PRINT_BUFFER;
+    
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::GetMessageData - return" ) ) );
+    }
+
+// ---------------------------------------------------------------------------
+// Get new data for condition listener.
+// Always get all the data available.
+// ---------------------------------------------------------------------------
+//
+void CSensrvChannelBuffer::GetConditionData(TSensrvTailIndexItem* aTailItem,
+                                            CSensrvChannelListener::TChannelDataParts& aDataParts)
+    {
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::GetConditionData" ) ) );
+
+    if( aTailItem == NULL )
+        return;
+    
+    TInt actualCount1(0);
+    TInt actualCount2(0);
+    
+    // Condition data is always cleared at every new data notification, so 
+    // it is unlikely that it ever will build up to more than maximum buffering count,
+    // or have two parts, unless SSY thread somehow manages to call BufferFilled twice
+    // or more times in a row without new data handling on server main thread. 
+    // However, it is theoretically possible, so check the available count
+    // and need for multiple parts.
+    // If further optimization of condition checking is required, this possibility can 
+    // probably be quite safely ignored and second data part gotten rid of.
+    if (!aTailItem->iConditionDataAvailable)
+        {
+        // No new data available, do nothing
+        BUFFER_TRACE((_L("#### No more condition data available")));
+        }        
+    else if (aTailItem->iConditionTailIndex >= iHeadIndex)
+        {
+        // Condition tail after (or at) head, so get up to end of the buffer
+        // and again from the beginning up to the head
+        actualCount1 = iValidEndIndex - aTailItem->iConditionTailIndex;
+        actualCount2 = iHeadIndex;
+        BUFFER_TRACE((_L("#### Two parts of condition data available")));
+        }
+    else
+        {
+        // Condition tail before head, so get up to head
+        actualCount1 = iHeadIndex - aTailItem->iConditionTailIndex;
+        BUFFER_TRACE((_L("#### One part of condition data available")));
+        }
+    
+    // Get data parts
+    TUint8* startPtr = const_cast<TUint8*>(iBuffer->Ptr());
+    TUint8* tailPtr = startPtr + aTailItem->iConditionTailIndex*iItemSize;
+
+    aDataParts.iFirstDataPart.Set(tailPtr, actualCount1*iItemSize);   
+    aDataParts.iSecondDataPart.Set(startPtr, actualCount2*iItemSize);        
+
+    // Reset tail
+    aTailItem->iConditionTailIndex = iHeadIndex;
+    aTailItem->iConditionDataAvailable = 0;
+
+    DEBUG_PRINT_BUFFER;
+    
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::GetConditionData - return" ) ) );
+    }
+
+// ---------------------------------------------------------------------------
+// Invalidates range of items starting from head index.
+// Adjusts valid and tail indexes accordingly.
+// ---------------------------------------------------------------------------
+//
+void CSensrvChannelBuffer::InvalidateRange(TInt aCount)
+    {
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::InvalidateRange(aCount: %d)" ), aCount ) );
+    
+    TInt invalidEnd(iHeadIndex+aCount);
+    
+    // Data loss occurs for items between iHeadIndex and invalidIndex,
+    // but only up to iValidEndIndex
+    TInt dataLossIndex(0);
+    if (invalidEnd > iValidEndIndex)
+        {
+        dataLossIndex = iValidEndIndex;
+        }
+    else
+        {
+        dataLossIndex = invalidEnd;
+        }
+
+    // Update tail indexes and data lost for tail indexes in invalidated area
+    for(TInt i = 0; i < iTailIndexArray.Count(); i++)
+        {
+        if (   iTailIndexArray[i]->iDataAvailable 
+            && iTailIndexArray[i]->iDataTailIndex >= iHeadIndex 
+            && iTailIndexArray[i]->iDataTailIndex < invalidEnd)
+            {
+            // Indicate missed data
+            iTailIndexArray[i]->iDataLostCount += dataLossIndex - iTailIndexArray[i]->iDataTailIndex;
+     
+            // Move tail to end of invalid range
+            if (invalidEnd >= iValidEndIndex)
+                {
+                // Roll tail to zero index at end of valid buffer.
+                iTailIndexArray[i]->iDataTailIndex = 0;
+                }
+            else
+                {
+                iTailIndexArray[i]->iDataTailIndex = invalidEnd;
+                }
+            
+            // It is necessary to update available amount after invalidation ate some of it.
+            UpdateDataAvailable(*(iTailIndexArray[i]), EFalse);
+            }
+        else
+            {
+            // Do not adjust, as tail is before head, at head (with no unread data),
+            // or beyond invalidation range.
+            // -> It cannot be affected by the invalidation
+            }
+        
+        // Update condition tail index. Should very rarely if ever come here.
+        // Only possible if SSY thread is able to make multiple buffer fills
+        // before server gets to handle new data available.
+        if (   iTailIndexArray[i]->iConditionDataAvailable 
+            && iTailIndexArray[i]->iConditionTailIndex >= iHeadIndex
+            && iTailIndexArray[i]->iConditionTailIndex < invalidEnd )
+            {
+            if (invalidEnd >= iValidEndIndex)
+                {
+                // Roll tail to zero index at end of valid buffer.
+                iTailIndexArray[i]->iConditionTailIndex = 0;
+                }
+            else
+                {
+                iTailIndexArray[i]->iConditionTailIndex = invalidEnd;
+                }
+            
+            // It is necessary to update available amount after invalidation ate some of it.
+            UpdateDataAvailable(*(iTailIndexArray[i]), EFalse);
+            }
+        else
+            {
+            // Do not adjust, as tail is before head, at head (with no unread data),
+            // or beyond invalidation range.
+            // -> It cannot be affected by the invalidation
+            }
+        }
+        
+    // Valid data ends at head index, unless it was beyond invalidated range.    
+    if (invalidEnd >= iValidEndIndex)
+        {
+        iValidEndIndex = iHeadIndex;
+        }
+
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::InvalidateRange - return" ) ) );
+    }
+
+// ---------------------------------------------------------------------------
+// Checks how much new data is available for listener.
+//
+// The data available is iHeadIndex - iDataTailIndex if iHeadIndex
+// is larger than iTailIndex, or iBufferLength - iDataTailIndex + iHeadIndex,
+// if iHeadIndex is smaller than iTailIndex.
+// ---------------------------------------------------------------------------
+//
+void CSensrvChannelBuffer::UpdateDataAvailable(TSensrvTailIndexItem& aTailItem,
+                                               TBool aMoreData)
+    {
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::UpdateDataAvailable(aTailItem.iListener: 0x%x, aMoreData: %d)" ), aTailItem.iListener, aMoreData ) );
+
+    // Update data available
+    if (aTailItem.iDataTailIndex != KSensrvChannelBufferUnusedTail)
+        {
+        if (aTailItem.iDataTailIndex == KSensrvChannelBufferUninitializedTail)
+            {
+            aTailItem.iDataAvailable = 0;
+            aTailItem.iDataTailIndex = iHeadIndex;
+            }
+        else if (aTailItem.iDataTailIndex == iHeadIndex)
+            {
+            if (aMoreData)
+                {
+                // The amount of available data increased with this update;
+                // being at head index means that buffer is full
+                aTailItem.iDataAvailable = iValidEndIndex;
+                }
+            else
+                {
+                // The amount of data potentially decreased with this update;
+                // being at headindex means there is no data available
+                aTailItem.iDataAvailable = 0;
+                }
+            }
+        else if (aTailItem.iDataTailIndex < iHeadIndex)
+            {
+            aTailItem.iDataAvailable = iHeadIndex - aTailItem.iDataTailIndex;
+            }
+        else // aTailItem.iDataTailIndex > iHeadIndex
+            {
+            aTailItem.iDataAvailable = iValidEndIndex - aTailItem.iDataTailIndex + iHeadIndex;
+            }    
+        }
+    
+    // Update condition data available
+    if (aTailItem.iConditionTailIndex != KSensrvChannelBufferUnusedTail)
+        {
+        if (aTailItem.iConditionTailIndex == KSensrvChannelBufferUninitializedTail)
+            {
+            aTailItem.iConditionDataAvailable = 0;
+            aTailItem.iConditionTailIndex = iHeadIndex;
+            }
+        else if (aTailItem.iConditionTailIndex == iHeadIndex)
+            {
+            if (aMoreData)
+                {
+                // The amount of available data increased with this update;
+                // being at head index means that buffer is full
+                aTailItem.iConditionDataAvailable = iValidEndIndex;
+                }
+            else
+                {
+                // The amount of data potentially decreased with this update;
+                // being at headindex means there is no data available
+                aTailItem.iConditionDataAvailable = 0;
+                }
+            }
+        else if (aTailItem.iConditionTailIndex < iHeadIndex)
+            {
+            aTailItem.iConditionDataAvailable = iHeadIndex - aTailItem.iConditionTailIndex;
+            }
+        else // aTailItem.iConditionTailIndex > iHeadIndex
+            {
+            aTailItem.iConditionDataAvailable = iValidEndIndex - aTailItem.iConditionTailIndex + iHeadIndex;
+            }    
+        }
+
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::UpdateDataAvailable - return. Data available: %d" ), aTailItem.iDataAvailable ) );
+    }
+    
+// ---------------------------------------------------------------------------
+// Returns tail index for listener
+// ---------------------------------------------------------------------------
+//
+TInt CSensrvChannelBuffer::GetTailIndex(CSensrvChannelListener* aListener)
+    {
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::GetTailIndex(aListener: 0x%x)" ), aListener ) );
+ 
+    TInt index(0);
+    
+    for(TInt i = 0; !index && i < iTailIndexArray.Count(); i++)
+        {
+        if (iTailIndexArray[i]->iListener == aListener)
+            {
+            index = i;
+            }
+        }
+        
+    if (!index)        
+        {
+        index = KErrNotFound;
+        }
+
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::GetTailIndex - return %d" ), index ) );
+    
+    return index;
+    }
+
+#ifdef BUFFER_TRACE_DEBUG        
+// ---------------------------------------------------------------------------
+// Prints out buffer details with RDebug
+// ---------------------------------------------------------------------------
+//
+void CSensrvChannelBuffer::DebugPrintBuffer()
+    {
+    BUFFER_TRACE((_L("#### iHeadIndex: %d, iValidEndIndex: %d, iRequestedFreeBlockLength: %d"), iHeadIndex, iValidEndIndex, iRequestedFreeBlockLength));
+    for(TInt i = 0; i < iTailIndexArray.Count(); i++)
+        {
+        BUFFER_TRACE((_L("#### iListener: 0x%x, iDataTailIndex: %d, iConditionTailIndex: %d, iDataLostCount: %d, iDataAvailable: %d, iConditionDataAvailable: %d"), 
+                      iTailIndexArray[i]->iListener,
+                      iTailIndexArray[i]->iDataTailIndex,
+                      iTailIndexArray[i]->iConditionTailIndex,
+                      iTailIndexArray[i]->iDataLostCount,
+                      iTailIndexArray[i]->iDataAvailable,
+                      iTailIndexArray[i]->iConditionDataAvailable));
+        }
+    }
+#endif // BUFFER_TRACE_DEBUG
+
+
+// ---------------------------------------------------------------------------
+// Get the initial data for listener to transaction data item
+// ---------------------------------------------------------------------------
+//
+void CSensrvChannelBuffer::GetInitialMessageData( CSensrvChannelListener::TChannelDataMessage& aMessageData )
+    {
+    COMPONENT_TRACE( ( _L( "Sensor Server - CSensrvChannelBuffer::GetInitialMessageData iLatestWrittenItemIndex %d" ), 
+        iLatestWrittenItemIndex ) );
+    
+    aMessageData.iDataItemCount = 0;
+    aMessageData.iDataLostCount = 0;
+    
+    if ( iLatestWrittenItemIndex >= 0 )
+        {
+        TUint8* itemPtr = const_cast<TUint8*>( iBuffer->Ptr() ) + iLatestWrittenItemIndex * iItemSize;
+        aMessageData.iFirstDataPart.Set( itemPtr, iItemSize );
+        aMessageData.iSecondDataPart.Set( KNullDesC8 );
+        aMessageData.iDataItemCount = 1;
+        }
+    
+    COMPONENT_TRACE( _L( "Sensor Server - CSensrvChannelBuffer::GetInitialMessageData - return" ) );
+    }
+