Update contrib.
1 // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
17 #include <e32std_private.h>
21 #include "user_config.h"
24 _LIT( KTestName, "TF_WRITE" );
25 RTest test( KTestName );
28 const TInt64 KRandomSeed1(MAKE_TINT64(0x3e000111,0xAFCBDF0F));
31 GLDEF_C void Panic( TPanicNo aPanic )
33 User::Panic( KTestName, aPanic );
37 // **********************************************************************
38 // Implementation of the writer classes
40 TWriteBase::TWriteBase( CWriteTest& aOwner )
45 void TWriteBase::CheckedWrite(TInt aPos,const TDesC8& aSrc)
48 test( iOwner.CompareAgainstFlash( aPos, aSrc ) );
52 TSimpleWrite::TSimpleWrite( CWriteTest& aOwner )
53 : TWriteBase( aOwner ), iDrive( aOwner.Drive() )
57 void TSimpleWrite::Write(TInt aPos,const TDesC8& aSrc)
60 // test( KErrNone == iDrive.Write( pos, aSrc ) );
61 TInt rv = iDrive.Write( pos, aSrc );
64 test.Printf( _L("TBusLocalDrive::Write returned %d"), rv );
71 TThreadWrite::TThreadWrite( CWriteTest& aOwner )
72 : TWriteBase( aOwner ), iDrive( aOwner.Drive() ),
73 iThreadHandle( aOwner.DummyThreadHandle() )
77 void TThreadWrite::Write(TInt aPos,const TDesC8& aSrc)
81 test( KErrNone == iDrive.Write( pos, aSrc.Length(), &aSrc, iThreadHandle, 0 ) );
83 test( KErrNone == iDrive.Write( pos, aSrc.Length(), &aSrc, KLocalMessageHandle, 0 ) );
88 void TThreadWrite::CheckedThreadWrite(TInt aPos, TInt aLength, const TDesC8& aSrc, TInt aDescOffset )
92 test( KErrNone == iDrive.Write( pos, aLength, &aSrc, iThreadHandle, aDescOffset ) );
94 test( KErrNone == iDrive.Write( pos, aLength, &aSrc, KLocalMessageHandle, aDescOffset ) );
96 test( iOwner.CompareAgainstFlash( aPos, aLength, aSrc, aDescOffset ) );
99 void TThreadWrite::CurrentThreadCheckedThreadWrite(TInt aPos, TInt aLength, const TDesC8& aSrc, TInt aDescOffset )
103 test( KErrNone == iDrive.Write( pos, aLength, &aSrc, RThread().Handle(), aDescOffset ) );
105 test( KErrNone == iDrive.Write( pos, aLength, &aSrc, KLocalMessageHandle, aDescOffset ) );
107 test( iOwner.CompareAgainstFlash( aPos, aLength, aSrc, aDescOffset ) );
110 // **********************************************************************
111 // Implementation of CBlockManager
113 CBlockManager::CBlockManager( TBusLocalDrive& aDrive, CWriteTest& aOwner )
114 : iDrive( aDrive ), iOwner( aOwner )
118 CBlockManager::~CBlockManager()
120 delete[] iEraseArray;
123 void CBlockManager::CreateL()
126 // Get size of Flash drive
128 test.Printf( _L("Reading block info...") );
129 TLocalDriveCapsV2Buf info;
131 TUint flashSize = I64LOW(info().iSize);
132 test( 0 == I64HIGH(info().iSize));
133 iBlockSize = info().iEraseBlockSize;
134 test( 0 == (iBlockSize & 3) );
135 iBlockCount = flashSize / iBlockSize;
136 test( 0 != iBlockCount );
138 test.Printf( _L("Flash block size=0x%x; block count=%d\n"), iBlockSize, iBlockCount );
140 iEraseArray = new(ELeave) TEraseStatus[iBlockCount];
141 test.Printf( _L("Erase status array created") );
145 void CBlockManager::EraseBlock( TInt aBlockNumber )
147 __ASSERT_ALWAYS( aBlockNumber < iBlockCount, Panic( EPanicEraseBlockOOR ) );
148 __ASSERT_ALWAYS( aBlockNumber < iBlockCount, Panic( EPanicEraseBlockNeg ) );
149 _LIT( KEraseMsg, "Erasing block %d" );
150 test.Printf( KEraseMsg, aBlockNumber );
151 test( KErrNone == iDrive.Format( BlockAddress( aBlockNumber ), iBlockSize ) );
152 VerifyErased( aBlockNumber );
153 iEraseArray[ aBlockNumber ] = EErased;
156 void CBlockManager::EraseAllBlocks()
158 _LIT( KEraseMsg, "Erasing all blocks" );
159 test.Printf( KEraseMsg );
160 for( TInt i = 0; i < iBlockCount; i++ )
166 void CBlockManager::VerifyErased( TInt aBlockNumber )
168 TUint offset = aBlockNumber * iBlockSize;
170 TBool failed = EFalse;
171 const TInt readBufLen = iReadBuffer.MaxLength();
173 for( TInt remaining = iBlockSize; remaining > 0 && !failed ;)
175 TInt r = iDrive.Read( offset, readBufLen, iReadBuffer );
178 test.Printf( _L("... FAIL: read failed (%d) at offset 0x%x\n"), r, offset );
179 test( KErrNone == r );
181 test( iReadBuffer.Length() == readBufLen );
183 const TUint32* p = (const TUint32*)iReadBuffer.Ptr();
184 for( TInt i = 0; i < readBufLen; i += 4 )
186 if( 0xFFFFFFFF != *p )
189 test.Printf( _L("... FAILED: byte @ offs=0x%x, read=0x%x, expected=0xFF\n"),
195 offset += readBufLen;
196 remaining -= readBufLen;
201 void CBlockManager::InitialiseSequentialBlockAllocator()
203 // Clears the erase status and resets to block zero
206 for( TInt i = 0; i < iBlockCount; i++ )
208 iEraseArray[i] = ENotErased;
214 TInt CBlockManager::NextErasedBlock()
216 if( iNextBlock >= iBlockCount )
221 if( ENotErased == iEraseArray[iNextBlock] )
223 EraseBlock( iNextBlock );
225 iEraseArray[iNextBlock] = ENotErased; // assume it is going to be used
229 void CBlockManager::InitialiseDataChunkAllocator()
231 iDataBlock = NextErasedBlock();
236 TUint CBlockManager::NextErasedDataChunk( TInt aRequiredLength, TInt aMultiple )
238 // Request a chunk of erased flash of size aRequiredLength bytes on a
239 // boundary of aMultiple bytes. E,g, to allocate a buffer on 12 bytes length
240 // on a 32-byte boundary, aRequiredLength = 12, aMultiple=12
242 // The byte count is rounded up to a multiple of 4 bytes
245 aRequiredLength = (aRequiredLength + 3) & ~0x3;
247 TUint chunkBase = ((iDataOffset + aMultiple - 1) / aMultiple) * aMultiple;
248 if( chunkBase > (TUint)iBlockSize || chunkBase + aRequiredLength > (TUint)iBlockSize )
250 iDataBlock = NextErasedBlock();
254 iDataOffset = ( chunkBase + aRequiredLength + 3) & ~0x3;
256 return BlockAddress( iDataBlock ) + chunkBase;
261 inline TInt CBlockManager::BlockCount() const
266 inline TInt CBlockManager::BlockSize() const
271 inline TInt CBlockManager::FlashSize() const
273 return iBlockSize * iBlockCount;
276 inline TUint CBlockManager::BlockAddress( TInt aBlockNumber ) const
278 return (TUint)aBlockNumber * (TUint)iBlockSize;
282 // **********************************************************************
283 // Implementation of CWriteTest
285 CWriteTest::~CWriteTest()
293 delete iSimpleWriter;
294 delete iThreadWriter;
298 void CWriteTest::CreateL()
301 // Load the device drivers
304 #ifndef SKIP_PDD_LOAD
305 test.Printf( _L("Loading %S\n"), &KLfsDriverName );
306 r = User::LoadPhysicalDevice( KLfsDriverName );
307 test( KErrNone == r || KErrAlreadyExists == r );
312 test( KErrNone == fs.Connect() );
315 test( KErrNone == fs.SetDefaultPath( _L("Z:\\") ) );
318 fs.FileSystemName( name, KLffsLogicalDriveNumber );
319 if( name.Length() > 0 )
321 test.Printf( _L("Unmounting drive") );
322 test( KErrNone == fs.DismountFileSystem( _L("Lffs"), KLffsLogicalDriveNumber) );
323 User::After( 2000000 );
324 test.Printf( _L("Drive unmounted") );
330 // Open a TBusLogicalDevice to it
332 test.Printf( _L("Opening media channel\n") );
333 TBool changedFlag = EFalse;
334 r = iDrive.Connect( KDriveNumber, changedFlag );
335 User::LeaveIfError( r );
336 iDriveOpened = ETrue;
339 // Initialise the block manager
341 iBlocks = new(ELeave) CBlockManager( iDrive, *this );
345 // Create a dummy thread that we can use to force
346 // other-thread write operations
349 test( KErrNone == iDummyThread.Create( _L("DUMMY"), DummyThread, 256, KMinHeapSize, KMinHeapSize, NULL ) );
351 test( KErrNone == iDummyThread.Create( _L("DUMMY"), DummyThread, KDefaultStackSize, KMinHeapSize, KMinHeapSize, NULL ) );
353 test.Printf( _L("Main thread handle=%d; dummy thread handle=%d"),
354 RThread().Handle(), DummyThreadHandle() );
357 // Create the writer classes
359 iSimpleWriter = new(ELeave) TSimpleWrite( *this );
360 iThreadWriter = new(ELeave) TThreadWrite( *this );
363 // Seed the pseudo-random number generator
365 iRandom.SetSeed( KRandomSeed1 );
368 test.Printf( _L("CWriteTest::CreateL complete\n") );
372 TInt CWriteTest::DummyThread( TAny* /* aParam */ )
374 // Thread does nothing at all
379 User::WaitForAnyRequest(); // just block
383 void CWriteTest::CreateRandomData( TDes8& aDestBuf, TInt aLength )
385 // Fills supplied descriptor with aLength bytes of pseudo-random test data
388 aDestBuf.SetLength( aLength );
389 TUint32* p = (TUint32*)aDestBuf.Ptr();
390 for( TInt j = aLength/4; j > 0 ; j-- )
392 *p++ = iRandom.Next();
397 TUint8* q = (TUint8*)p;
398 for( TInt k = aLength & 3; k > 0; k-- )
400 *q++ = (TUint8)iRandom.Next();
406 TBool CWriteTest::CheckOnes( TUint aFlashOffset, TInt aLength )
408 // Checks that aLength bytes of data from offset aFlashOffset
412 TUint offset = aFlashOffset;
414 TBool failed = EFalse;
415 const TInt readBufLen = iReadBuffer.MaxLength();
417 for( TInt remaining = aLength; remaining > 0 && !failed ;)
419 TInt readLen = Min( remaining, readBufLen );
420 TInt r = iDrive.Read( offset, readLen, iReadBuffer );
423 test.Printf( _L("... FAIL: read failed (%d) at offset 0x%x\n"), r, offset );
424 test( KErrNone == r );
426 test( iReadBuffer.Length() == readLen );
428 const TUint8* p = iReadBuffer.Ptr();
429 for( TInt i = 0; i < readLen; ++i )
434 test.Printf( _L("... FAILED: byte @ offs=0x%x, read=0x%x, expected=0xFF\n"),
441 remaining -= readLen;
448 TBool CWriteTest::CompareAgainstFlash( TInt aFlashOffset, TInt aLength, const TDesC8& aDes, TInt aDescOffset )
450 // Checks that the data in aDes matches that in the Flash at position
452 // The test starts at offset aDescOffset in aSampleData. aLength bytes
456 __ASSERT_ALWAYS( aDescOffset + aLength <= aDes.Length(), Panic( EPanicCompareDescOverflow ) );
457 TInt dataLength = aLength;
458 const TUint8* srcPtr = aDes.Ptr() + aDescOffset;
460 TUint offset = aFlashOffset;
462 TBool failed = EFalse;
463 const TInt readBufLen = iReadBuffer.MaxLength();
465 while( (dataLength > 0) && !failed )
467 TInt len = Min( dataLength, readBufLen );
468 TInt r = iDrive.Read( offset, len, iReadBuffer );
471 test.Printf( _L("... FAIL: read failed (%d) at offset 0x%x\n"), r, offset );
472 test( KErrNone == r );
474 test( iReadBuffer.Length() == len );
476 if( 0 != Mem::Compare( srcPtr, len, iReadBuffer.Ptr(), len ) )
478 test.Printf( _L("... FAIL: mismatch around offset 0x%x\n"), offset );
489 TBool CWriteTest::CompareAgainstFlash( TInt aFlashOffset, const TDesC8& aDes )
491 // Checks that the data in aDes matches that in the Flash at position
493 // aDes->Length() bytes are tested.
496 return CompareAgainstFlash( aFlashOffset, aDes.Length(), aDes, 0 );
500 void CWriteTest::SimpleWriteTest()
502 test.Next( _L("Simple write test, simple write function") );
503 DoSimpleWriteTest( *iSimpleWriter );
506 void CWriteTest::SimpleThreadWriteTest()
508 test.Next( _L("Simple write test, thread write function") );
509 DoSimpleWriteTest( *iThreadWriter );
513 void CWriteTest::DoSimpleWriteTest( MGeneralizedWrite& aWriter )
515 // Writes some random test data to the start of a block, checks that
516 // it is written correctly and that the source data isn't modified
519 TInt blockNo = iBlocks->NextErasedBlock();
520 TUint blockBase = iBlocks->BlockAddress( blockNo );
522 TBuf8<512> randomData;
523 CreateRandomData( randomData, randomData.MaxLength() );
525 TBuf8<512> randomDataDuplicate;
526 randomDataDuplicate.Copy( randomData );
527 test( randomDataDuplicate == randomData );
529 TBuf8<sizeof(TPtr)> ptrCopy; // used to take copies of descriptors
532 // Write using a constant descriptor TPtrC
534 test.Printf( _L("Write using TPtrC") );
535 TPtrC8 ptrC( randomData );
536 ptrCopy.Copy( (TUint8*)&ptrC, sizeof(ptrC) );
538 aWriter.CheckedWrite( blockBase + 0, ptrC );
540 test.Printf( _L("Check descriptor not modified by write function") );
541 test( 0 == Mem::Compare( (TUint8*)&ptrC, sizeof(ptrC), ptrCopy.Ptr(), sizeof(ptrC) ) );
543 test.Printf( _L("Check data not modified by write function") );
544 test( randomDataDuplicate == randomData );
547 // Write using a modifiable descriptor TPtr
549 test.Printf( _L("Write using TPtr") );
550 TPtr8 ptr( (TUint8*)randomData.Ptr(), randomData.Length(), randomData.Length() );
551 ptrCopy.Copy( (TUint8*)&ptr, sizeof(ptr) );
553 aWriter.CheckedWrite( blockBase + 1024, ptr );
555 test.Printf( _L("Check descriptor not modified by write function") );
556 test( 0 == Mem::Compare( (TUint8*)&ptr, sizeof(ptr), ptrCopy.Ptr(), sizeof(ptr) ) );
558 test.Printf( _L("Check data not modified by write function") );
559 test( randomDataDuplicate == randomData );
562 // Write using a modifiable descriptor TBuf
564 test.Printf( _L("Write using TBuf") );
566 aWriter.CheckedWrite( blockBase + 2048, randomData );
568 test.Printf( _L("Check descriptor not modified by write function") );
569 test( ptrC.Ptr() == randomData.Ptr() );
570 test( 512 == randomData.Length() );
571 test( 512 == randomData.MaxLength() );
573 test.Printf( _L("Check data not modified by write function") );
574 test( randomDataDuplicate == randomData );
577 // Read the data back and check it matches
579 test.Printf( _L("Reading data back with TBusLocalDrive::Read") );
580 test( KErrNone == iDrive.Read( blockBase + 0, 512, randomDataDuplicate ) );
581 test( randomDataDuplicate == randomData );
582 test( KErrNone == iDrive.Read( blockBase + 1024, 512, randomDataDuplicate ) );
583 test( randomDataDuplicate == randomData );
584 test( KErrNone == iDrive.Read( blockBase + 2048, 512, randomDataDuplicate ) );
585 test( randomDataDuplicate == randomData );
590 void CWriteTest::AlignedWriteTest()
592 test.Next( _L("Aligned write test, simple write function") );
593 DoAlignedWriteTest( *iSimpleWriter );
596 void CWriteTest::AlignedThreadWriteTest()
598 test.Next( _L("Aligned write test, thread write function") );
599 DoAlignedWriteTest( *iThreadWriter );
603 void CWriteTest::DoAlignedWriteTest( MGeneralizedWrite& aWriter )
605 // Writes data of various lengths to word-aligned addresses
608 iBlocks->InitialiseDataChunkAllocator();
612 _LIT( KWriteMsg, " writing %d bytes @0x%x" );
614 test.Printf( _L("Testing small writes") );
616 for( TInt length = 1; length < 16; length++ )
618 CreateRandomData( data, length );
620 // get a 32-byte data chunk on a word boundary
621 TUint offset = iBlocks->NextErasedDataChunk( 32, 4 );
623 test.Printf( KWriteMsg, length, offset );
624 aWriter.CheckedWrite( offset, data );
625 // check that the section after the data still contains all ones
626 test( CheckOnes( offset + length, 32 - length ) );
630 test.Printf( _L("Testing large writes") );
631 for( TInt length = 512-32; length <= 512 ; length++ )
633 CreateRandomData( data, length );
635 // get a 544-byte data chunk on a word boundary
636 TUint offset = iBlocks->NextErasedDataChunk( 544, 4 );
638 test.Printf( KWriteMsg, length, offset );
639 aWriter.CheckedWrite( offset, data );
641 // check that the section after the data still contains all ones
642 test( CheckOnes( offset + length, 544 - length ) );
649 void CWriteTest::UnalignedWriteTest()
651 test.Next( _L("Unaligned write test, simple write function") );
652 DoUnalignedWriteTest( *iSimpleWriter );
655 void CWriteTest::UnalignedThreadWriteTest()
657 test.Next( _L("Unaligned write test, thread write function") );
658 DoUnalignedWriteTest( *iThreadWriter );
662 void CWriteTest::DoUnalignedWriteTest( MGeneralizedWrite& aWriter )
664 // Tests writing to unaligned addresses. "Unaligned" here means
665 // addresses that are not on a word boundary.
670 _LIT( KWriteMsg, " writing 32 bytes @0x%x" );
673 for( TInt offset = 1; offset < 32; offset++ )
675 CreateRandomData( data, data.MaxLength() );
678 // get a 64-byte data chunk on a 256-byte boundary, then
679 // start the write at <offset> bytes into this buffer
681 TUint dataChunk = iBlocks->NextErasedDataChunk( 64, 256 );
683 test.Printf( KWriteMsg, dataChunk + offset );
684 aWriter.CheckedWrite( dataChunk + offset, data );
686 _LIT( KBeforeMsg, " checking unused portion before data" );
687 test.Printf( KBeforeMsg );
688 test( CheckOnes( dataChunk, offset ) );
690 // check that the section after the data still contains all ones
691 _LIT( KAfterMsg, " checking unused portion after data" );
692 test.Printf( KAfterMsg );
693 test( CheckOnes( dataChunk + offset + data.Length(), 64 - offset - data.Length() ) );
699 void CWriteTest::OffsetDescriptorAlignedWriteTest()
701 // Tests writing using an offset into the source data buffer. Writes
702 // are done to word-aligned destination addresses.
705 test.Next( _L("Offset-desc write test, aligned dest address") );
709 _LIT( KWriteMsg, " writing 32 bytes from offset %d to @0x%x" );
711 // CreateRandomData( data, data.MaxLength() );
713 for( TInt i = 0; i < 64; i++ )
718 for( TInt descOffset = 1; descOffset < 32; descOffset++ )
721 // Get a 32-byte data chunk on a word boundary.
723 TUint dataChunk = iBlocks->NextErasedDataChunk( 32, 4 );
725 test.Printf( KWriteMsg, descOffset, dataChunk );
726 iThreadWriter->CheckedThreadWrite( dataChunk, 32, data, descOffset );
729 // Read the data back out and check it matches
731 _LIT( KReadBackMsg, "Reading back data" );
732 test.Printf( KReadBackMsg );
734 iDrive.Read( dataChunk, 32, readData );
735 TPtrC8 ptr( data.Ptr() + descOffset, 32 );
736 test( ptr == readData );
741 void CWriteTest::OffsetDescriptorUnalignedWriteTest()
743 // This is a variation of OffsetDescriptorAlignedWriteTest that
744 // also writes to non-word-aligned destionation addresses.
747 test.Next( _L("Offset-desc write test, unaligned dest address") );
751 _LIT( KWriteMsg, " writing 32 bytes from offset %d to @0x%x" );
753 CreateRandomData( data, data.MaxLength() );
755 for( TInt descOffset = 1; descOffset < 32; descOffset++ )
757 for( TInt unalign = 1; unalign < 4; unalign++ )
760 // Get a 40-byte data chunk on a word boundary.
762 TUint dataChunk = iBlocks->NextErasedDataChunk( 40, 4 );
763 TUint destOffset = dataChunk + unalign;
765 test.Printf( KWriteMsg, descOffset, destOffset );
766 iThreadWriter->CheckedThreadWrite( destOffset, 32, data, descOffset );
769 // Read the data back out and check it matches
771 _LIT( KReadBackMsg, "Reading back data" );
772 test.Printf( KReadBackMsg );
774 iDrive.Read( destOffset, 32, readData );
775 TPtrC8 ptr( data.Ptr() + descOffset, 32 );
776 test( ptr == readData );
782 void CWriteTest::OffsetDescriptorCurrentThreadAlignedWriteTest()
784 // Tests writing using an offset into the source data buffer. Writes
785 // are done to word-aligned destination addresses. This uses the
786 // thread variant of the write function but passes the handle
790 test.Next( _L("Offset-desc write test, current thread, aligned dest address") );
794 _LIT( KWriteMsg, " writing 32 bytes from offset %d to @0x%x" );
796 // CreateRandomData( data, data.MaxLength() );
798 for( TInt i = 0; i < 64; i++ )
803 for( TInt descOffset = 1; descOffset < 32; descOffset++ )
806 // Get a 32-byte data chunk on a word boundary.
808 TUint dataChunk = iBlocks->NextErasedDataChunk( 32, 4 );
810 test.Printf( KWriteMsg, descOffset, dataChunk );
811 iThreadWriter->CurrentThreadCheckedThreadWrite( dataChunk, 32, data, descOffset );
814 // Read the data back out and check it matches
816 _LIT( KReadBackMsg, "Reading back data" );
817 test.Printf( KReadBackMsg );
819 iDrive.Read( dataChunk, 32, readData );
820 TPtrC8 ptr( data.Ptr() + descOffset, 32 );
821 test( ptr == readData );
826 void CWriteTest::OffsetDescriptorCurrentThreadUnalignedWriteTest()
828 // This is a variation of OffsetDescriptorCurrentThreadAlignedWriteTest
829 // that also writes to non-word-aligned destionation addresses.
832 test.Next( _L("Offset-desc write test, current thread, unaligned dest address") );
836 _LIT( KWriteMsg, " writing 32 bytes from offset %d to @0x%x" );
838 CreateRandomData( data, data.MaxLength() );
840 for( TInt descOffset = 1; descOffset < 32; descOffset++ )
842 for( TInt unalign = 1; unalign < 4; unalign++ )
845 // Get a 40-byte data chunk on a word boundary.
847 TUint dataChunk = iBlocks->NextErasedDataChunk( 40, 4 );
848 TUint destOffset = dataChunk + unalign;
850 test.Printf( KWriteMsg, descOffset, destOffset );
851 iThreadWriter->CurrentThreadCheckedThreadWrite( destOffset, 32, data, descOffset );
854 // Read the data back out and check it matches
856 _LIT( KReadBackMsg, "Reading back data" );
857 test.Printf( KReadBackMsg );
859 iDrive.Read( destOffset, 32, readData );
860 TPtrC8 ptr( data.Ptr() + descOffset, 32 );
861 test( ptr == readData );
868 void CWriteTest::JoinedWriteTest()
870 // Makes two consecutive writes. Checks that the complete
871 // data block was written correctly. The data is written within
872 // a 64-byte window and the join position is moved along to each
876 test.Next( _L("Joined write test, simple writes") );
879 // Reinitialise the chunk allocator
881 iBlocks->InitialiseDataChunkAllocator();
883 for( TInt join = 1; join < 63; join++ )
886 CreateRandomData( fullData, fullData.MaxLength() );
889 // Create two TPtrC8s to the two parts of the data
891 TPtrC8 first( fullData.Ptr(), join );
892 TPtrC8 second( fullData.Ptr() + join, fullData.MaxLength() - join );
893 __ASSERT_ALWAYS( first.Length() + second.Length() == 64, Panic( EPanicJoinMaths ) );
896 // Get a location in the Flash to write to
898 TUint dataChunk = iBlocks->NextErasedDataChunk( 64, 64 );
901 // Write the two halves of the data
903 _LIT( KWriteMsg, " writing %d bytes @ 0x%x and %d bytes @ 0x%x" );
904 test.Printf( KWriteMsg, first.Length(), dataChunk,
905 second.Length(), dataChunk + first.Length() );
906 test( KErrNone == iDrive.Write( dataChunk, first ) );
907 test( KErrNone == iDrive.Write( dataChunk + first.Length(), second ) );
912 _LIT( KCompareMsg, " comparing data against Flash" );
913 test.Printf( KCompareMsg );
914 test( CompareAgainstFlash( dataChunk, fullData ) );
919 void CWriteTest::JoinedThreadWriteTest()
921 // Makes two consecutive writes. Checks that the complete
922 // data block was written correctly. The data is written within
923 // a 64-byte window and the join position is moved along to each
926 // This is similar to JoinedWriteTest except that the thread write
927 // function is used with a descriptor offset to chop up the
932 test.Next( _L("Joined write test, thread writes") );
935 // Reinitialise the chunk allocator
937 iBlocks->InitialiseDataChunkAllocator();
939 for( TInt join = 1; join < 63; join++ )
942 CreateRandomData( fullData, fullData.MaxLength() );
945 // Get a location in the Flash to write to
947 TUint dataChunk = iBlocks->NextErasedDataChunk( 64, 64 );
950 // Write the two halves of the data
952 _LIT( KWriteMsg, " writing %d bytes @ 0x%x and %d bytes @ 0x%x" );
953 test.Printf( KWriteMsg, join, dataChunk, 64 - join, dataChunk + join );
955 test( KErrNone == iDrive.Write( dataChunk, join, &fullData, DummyThreadHandle(), 0 ) );
956 test( KErrNone == iDrive.Write( dataChunk + join, 64-join, &fullData, DummyThreadHandle(), join ) );
958 test( KErrNone == iDrive.Write( dataChunk, join, &fullData, KLocalMessageHandle, 0 ) );
959 test( KErrNone == iDrive.Write( dataChunk + join, 64-join, &fullData, KLocalMessageHandle, join ) );
966 _LIT( KCompareMsg, " comparing data against Flash" );
967 test.Printf( KCompareMsg );
968 test( CompareAgainstFlash( dataChunk, fullData ) );
974 void CWriteTest::SingleBitOverwriteTest()
976 // Tests overwriting single bits within a byte. a 32-byte
977 // section of Flash is filled with data, with one byte initially
978 // 0xFF. A bit is then written to zero and the whole data block
982 test.Next( _L("Single bit overwrite test") );
984 iBlocks->InitialiseDataChunkAllocator();
986 for( TInt testByteOffset = 0; testByteOffset < 32; testByteOffset++ )
988 for( TInt testBitNumber = 0; testBitNumber < 8; testBitNumber++ )
991 CreateRandomData( data, data.MaxLength() );
992 data[ testByteOffset ] = 0xFF; // force test byte to 0xFF
994 TUint flashOffset = iBlocks->NextErasedDataChunk( 32, 32 );
996 _LIT( KWriteMsg, "writing test data @0x%x, test byte offset=%d; test bit #%d");
997 test.Printf( KWriteMsg, flashOffset, testByteOffset, testBitNumber );
999 iSimpleWriter->CheckedWrite( flashOffset, data );
1001 // clear the test bit
1004 byte[0] = ~(1 << testBitNumber);
1005 data[ testByteOffset ] = byte[0];
1007 iSimpleWriter->CheckedWrite( flashOffset + testByteOffset, byte );
1009 // check that the contents of the Flash matches the buffer
1010 test( CompareAgainstFlash( flashOffset, data ) );
1015 void CWriteTest::TwoBitOverwriteTest()
1017 // Tests overwriting two bits within a byte. a 32-byte
1018 // section of Flash is filled with data, with one byte initially
1019 // 0xFF. Two bits are then written to zero and the whole data block
1023 static const TUint pattConv[16] =
1025 // used to create a string representation of binary value
1026 0x0000, 0x0001, 0x0010, 0x0011, 0x0100, 0x0101, 0x0110, 0x0111,
1027 0x1000, 0x1001, 0x1010, 0x1011, 0x1100, 0x1101, 0x1110, 0x1111
1029 test.Next( _L("Two bit overwrite test") );
1031 for( TInt testByteOffset = 0; testByteOffset < 32; testByteOffset++ )
1033 for( TInt testBitJ = 0; testBitJ < 7; testBitJ++ )
1035 for( TInt testBitK = testBitJ+1; testBitK < 8; testBitK++ )
1038 CreateRandomData( data, data.MaxLength() );
1039 data[ testByteOffset ] = 0xFF; // force test byte to 0xFF
1041 TUint flashOffset = iBlocks->NextErasedDataChunk( 32, 32 );
1043 TUint8 testPattern = ~((1 << testBitJ) | (1 << testBitK));
1045 _LIT( KWriteMsg, "writing test data @0x%x, test byte offset=%d; test pattern = %04x%04x");
1046 test.Printf( KWriteMsg, flashOffset, testByteOffset,
1047 pattConv[ testPattern >> 4 ], pattConv[ testPattern&0xF ] );
1049 iSimpleWriter->CheckedWrite( flashOffset, data );
1053 byte[0] = testPattern;
1054 data[ testByteOffset ] = testPattern;
1056 iSimpleWriter->CheckedWrite( flashOffset + testByteOffset, byte );
1058 // check that the contents of the Flash matches the buffer
1059 test( CompareAgainstFlash( flashOffset, data ) );
1066 void CWriteTest::RunSimulationTest()
1068 // A simulation of the way the LFFS filesystem will use a Flash block
1069 // Alternately writes 24 bytes to bottom of block, 512 bytes to top,
1070 // clears a bit in the 24-byte block. Repeats until block is full.
1073 test.Next( _L("Simulation test") );
1075 TUint blockBase = iBlocks->BlockAddress( iBlocks->NextErasedBlock() );
1077 TUint lowAddress = blockBase;
1078 TUint highAddress = blockBase + iBlocks->BlockSize() - 512;
1081 TBuf8<512> highData;
1082 TPtrC8 overwritePtr( lowData.Ptr(), 1 );
1084 while( lowAddress + 24 < highAddress )
1086 CreateRandomData( lowData, lowData.MaxLength() );
1087 CreateRandomData( highData, highData.MaxLength() );
1088 lowData[0] = 0xE7; // just some non-0xFF value
1090 _LIT( KWriteMsg, "Writing block size 24 @ 0x%x; block size 512 @ 0x%x" );
1091 test.Printf( KWriteMsg, lowAddress, highAddress );
1093 iSimpleWriter->CheckedWrite( lowAddress, lowData );
1094 iSimpleWriter->Write( highAddress, highData );
1096 // Overwrite the byte
1098 iSimpleWriter->Write( lowAddress, overwritePtr );
1100 test( CompareAgainstFlash( lowAddress, lowData ) );
1101 test( CompareAgainstFlash( highAddress, highData ) );
1103 lowAddress += lowData.Length();
1104 highAddress -= highData.Length();
1110 void CWriteTest::DoTests()
1112 // Main test dispatcher
1115 test.Next( _L("Erasing all blocks") );
1116 iBlocks->InitialiseSequentialBlockAllocator();
1117 iBlocks->EraseAllBlocks();
1120 // Basic tests that we can write data correctly without corrupting
1121 // the source buffer
1124 SimpleThreadWriteTest();
1127 // Test aligned writes of various lengths
1130 AlignedThreadWriteTest();
1133 // Test writing to unaligned locations
1135 UnalignedWriteTest();
1136 UnalignedThreadWriteTest();
1139 // Test writes with offset into source desriptor
1141 OffsetDescriptorCurrentThreadAlignedWriteTest();
1142 OffsetDescriptorCurrentThreadUnalignedWriteTest();
1143 OffsetDescriptorAlignedWriteTest();
1144 OffsetDescriptorUnalignedWriteTest();
1147 // Test two consecutive writes
1150 JoinedThreadWriteTest();
1153 // Test that we can overwrite bits
1155 SingleBitOverwriteTest();
1156 TwoBitOverwriteTest();
1159 // A simulation test of LFFS usage
1161 RunSimulationTest();
1176 test.Start(_L("Testing media read operations"));
1178 CWriteTest writeTest;
1179 TRAPD( ret, writeTest.CreateL() );
1180 test( KErrNone == ret );
1181 writeTest.DoTests();