0
|
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".
|
|
7 |
//
|
|
8 |
// Initial Contributors:
|
|
9 |
// Nokia Corporation - initial contribution.
|
|
10 |
//
|
|
11 |
// Contributors:
|
|
12 |
//
|
|
13 |
// Description:
|
|
14 |
//
|
|
15 |
|
|
16 |
#include <e32std.h>
|
|
17 |
#include <e32std_private.h>
|
|
18 |
#include <e32svr.h>
|
|
19 |
#include <e32test.h>
|
|
20 |
#include "randgen.h"
|
|
21 |
#include "user_config.h"
|
|
22 |
#include "tf_write.h"
|
|
23 |
|
|
24 |
_LIT( KTestName, "TF_WRITE" );
|
|
25 |
RTest test( KTestName );
|
|
26 |
|
|
27 |
|
|
28 |
const TInt64 KRandomSeed1(MAKE_TINT64(0x3e000111,0xAFCBDF0F));
|
|
29 |
|
|
30 |
|
|
31 |
GLDEF_C void Panic( TPanicNo aPanic )
|
|
32 |
{
|
|
33 |
User::Panic( KTestName, aPanic );
|
|
34 |
}
|
|
35 |
|
|
36 |
|
|
37 |
// **********************************************************************
|
|
38 |
// Implementation of the writer classes
|
|
39 |
|
|
40 |
TWriteBase::TWriteBase( CWriteTest& aOwner )
|
|
41 |
: iOwner( aOwner )
|
|
42 |
{
|
|
43 |
}
|
|
44 |
|
|
45 |
void TWriteBase::CheckedWrite(TInt aPos,const TDesC8& aSrc)
|
|
46 |
{
|
|
47 |
Write( aPos, aSrc );
|
|
48 |
test( iOwner.CompareAgainstFlash( aPos, aSrc ) );
|
|
49 |
}
|
|
50 |
|
|
51 |
|
|
52 |
TSimpleWrite::TSimpleWrite( CWriteTest& aOwner )
|
|
53 |
: TWriteBase( aOwner ), iDrive( aOwner.Drive() )
|
|
54 |
{
|
|
55 |
}
|
|
56 |
|
|
57 |
void TSimpleWrite::Write(TInt aPos,const TDesC8& aSrc)
|
|
58 |
{
|
|
59 |
TInt64 pos( aPos );
|
|
60 |
// test( KErrNone == iDrive.Write( pos, aSrc ) );
|
|
61 |
TInt rv = iDrive.Write( pos, aSrc );
|
|
62 |
if( KErrNone != rv )
|
|
63 |
{
|
|
64 |
test.Printf( _L("TBusLocalDrive::Write returned %d"), rv );
|
|
65 |
test( EFalse );
|
|
66 |
}
|
|
67 |
}
|
|
68 |
|
|
69 |
|
|
70 |
|
|
71 |
TThreadWrite::TThreadWrite( CWriteTest& aOwner )
|
|
72 |
: TWriteBase( aOwner ), iDrive( aOwner.Drive() ),
|
|
73 |
iThreadHandle( aOwner.DummyThreadHandle() )
|
|
74 |
{
|
|
75 |
}
|
|
76 |
|
|
77 |
void TThreadWrite::Write(TInt aPos,const TDesC8& aSrc)
|
|
78 |
{
|
|
79 |
TInt64 pos( aPos );
|
|
80 |
#if 0
|
|
81 |
test( KErrNone == iDrive.Write( pos, aSrc.Length(), &aSrc, iThreadHandle, 0 ) );
|
|
82 |
#else
|
|
83 |
test( KErrNone == iDrive.Write( pos, aSrc.Length(), &aSrc, KLocalMessageHandle, 0 ) );
|
|
84 |
#endif
|
|
85 |
}
|
|
86 |
|
|
87 |
|
|
88 |
void TThreadWrite::CheckedThreadWrite(TInt aPos, TInt aLength, const TDesC8& aSrc, TInt aDescOffset )
|
|
89 |
{
|
|
90 |
TInt64 pos( aPos );
|
|
91 |
#if 0
|
|
92 |
test( KErrNone == iDrive.Write( pos, aLength, &aSrc, iThreadHandle, aDescOffset ) );
|
|
93 |
#else
|
|
94 |
test( KErrNone == iDrive.Write( pos, aLength, &aSrc, KLocalMessageHandle, aDescOffset ) );
|
|
95 |
#endif
|
|
96 |
test( iOwner.CompareAgainstFlash( aPos, aLength, aSrc, aDescOffset ) );
|
|
97 |
}
|
|
98 |
|
|
99 |
void TThreadWrite::CurrentThreadCheckedThreadWrite(TInt aPos, TInt aLength, const TDesC8& aSrc, TInt aDescOffset )
|
|
100 |
{
|
|
101 |
TInt64 pos( aPos );
|
|
102 |
#if 0
|
|
103 |
test( KErrNone == iDrive.Write( pos, aLength, &aSrc, RThread().Handle(), aDescOffset ) );
|
|
104 |
#else
|
|
105 |
test( KErrNone == iDrive.Write( pos, aLength, &aSrc, KLocalMessageHandle, aDescOffset ) );
|
|
106 |
#endif
|
|
107 |
test( iOwner.CompareAgainstFlash( aPos, aLength, aSrc, aDescOffset ) );
|
|
108 |
}
|
|
109 |
|
|
110 |
// **********************************************************************
|
|
111 |
// Implementation of CBlockManager
|
|
112 |
|
|
113 |
CBlockManager::CBlockManager( TBusLocalDrive& aDrive, CWriteTest& aOwner )
|
|
114 |
: iDrive( aDrive ), iOwner( aOwner )
|
|
115 |
{
|
|
116 |
}
|
|
117 |
|
|
118 |
CBlockManager::~CBlockManager()
|
|
119 |
{
|
|
120 |
delete[] iEraseArray;
|
|
121 |
}
|
|
122 |
|
|
123 |
void CBlockManager::CreateL()
|
|
124 |
{
|
|
125 |
//
|
|
126 |
// Get size of Flash drive
|
|
127 |
//
|
|
128 |
test.Printf( _L("Reading block info...") );
|
|
129 |
TLocalDriveCapsV2Buf info;
|
|
130 |
iDrive.Caps(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 );
|
|
137 |
|
|
138 |
test.Printf( _L("Flash block size=0x%x; block count=%d\n"), iBlockSize, iBlockCount );
|
|
139 |
|
|
140 |
iEraseArray = new(ELeave) TEraseStatus[iBlockCount];
|
|
141 |
test.Printf( _L("Erase status array created") );
|
|
142 |
}
|
|
143 |
|
|
144 |
|
|
145 |
void CBlockManager::EraseBlock( TInt aBlockNumber )
|
|
146 |
{
|
|
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;
|
|
154 |
}
|
|
155 |
|
|
156 |
void CBlockManager::EraseAllBlocks()
|
|
157 |
{
|
|
158 |
_LIT( KEraseMsg, "Erasing all blocks" );
|
|
159 |
test.Printf( KEraseMsg );
|
|
160 |
for( TInt i = 0; i < iBlockCount; i++ )
|
|
161 |
{
|
|
162 |
EraseBlock( i );
|
|
163 |
}
|
|
164 |
}
|
|
165 |
|
|
166 |
void CBlockManager::VerifyErased( TInt aBlockNumber )
|
|
167 |
{
|
|
168 |
TUint offset = aBlockNumber * iBlockSize;
|
|
169 |
|
|
170 |
TBool failed = EFalse;
|
|
171 |
const TInt readBufLen = iReadBuffer.MaxLength();
|
|
172 |
|
|
173 |
for( TInt remaining = iBlockSize; remaining > 0 && !failed ;)
|
|
174 |
{
|
|
175 |
TInt r = iDrive.Read( offset, readBufLen, iReadBuffer );
|
|
176 |
if( r != KErrNone )
|
|
177 |
{
|
|
178 |
test.Printf( _L("... FAIL: read failed (%d) at offset 0x%x\n"), r, offset );
|
|
179 |
test( KErrNone == r );
|
|
180 |
}
|
|
181 |
test( iReadBuffer.Length() == readBufLen );
|
|
182 |
|
|
183 |
const TUint32* p = (const TUint32*)iReadBuffer.Ptr();
|
|
184 |
for( TInt i = 0; i < readBufLen; i += 4 )
|
|
185 |
{
|
|
186 |
if( 0xFFFFFFFF != *p )
|
|
187 |
{
|
|
188 |
failed = ETrue;
|
|
189 |
test.Printf( _L("... FAILED: byte @ offs=0x%x, read=0x%x, expected=0xFF\n"),
|
|
190 |
offset+i, p[0] );
|
|
191 |
test(EFalse);
|
|
192 |
}
|
|
193 |
++p;
|
|
194 |
}
|
|
195 |
offset += readBufLen;
|
|
196 |
remaining -= readBufLen;
|
|
197 |
}
|
|
198 |
}
|
|
199 |
|
|
200 |
|
|
201 |
void CBlockManager::InitialiseSequentialBlockAllocator()
|
|
202 |
//
|
|
203 |
// Clears the erase status and resets to block zero
|
|
204 |
//
|
|
205 |
{
|
|
206 |
for( TInt i = 0; i < iBlockCount; i++ )
|
|
207 |
{
|
|
208 |
iEraseArray[i] = ENotErased;
|
|
209 |
}
|
|
210 |
iNextBlock = 0;
|
|
211 |
}
|
|
212 |
|
|
213 |
|
|
214 |
TInt CBlockManager::NextErasedBlock()
|
|
215 |
{
|
|
216 |
if( iNextBlock >= iBlockCount )
|
|
217 |
{
|
|
218 |
iNextBlock = 0;
|
|
219 |
}
|
|
220 |
|
|
221 |
if( ENotErased == iEraseArray[iNextBlock] )
|
|
222 |
{
|
|
223 |
EraseBlock( iNextBlock );
|
|
224 |
}
|
|
225 |
iEraseArray[iNextBlock] = ENotErased; // assume it is going to be used
|
|
226 |
return iNextBlock;
|
|
227 |
}
|
|
228 |
|
|
229 |
void CBlockManager::InitialiseDataChunkAllocator()
|
|
230 |
{
|
|
231 |
iDataBlock = NextErasedBlock();
|
|
232 |
iDataOffset = 0;
|
|
233 |
}
|
|
234 |
|
|
235 |
|
|
236 |
TUint CBlockManager::NextErasedDataChunk( TInt aRequiredLength, TInt aMultiple )
|
|
237 |
//
|
|
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
|
|
241 |
//
|
|
242 |
// The byte count is rounded up to a multiple of 4 bytes
|
|
243 |
//
|
|
244 |
{
|
|
245 |
aRequiredLength = (aRequiredLength + 3) & ~0x3;
|
|
246 |
|
|
247 |
TUint chunkBase = ((iDataOffset + aMultiple - 1) / aMultiple) * aMultiple;
|
|
248 |
if( chunkBase > (TUint)iBlockSize || chunkBase + aRequiredLength > (TUint)iBlockSize )
|
|
249 |
{
|
|
250 |
iDataBlock = NextErasedBlock();
|
|
251 |
chunkBase = 0;
|
|
252 |
}
|
|
253 |
|
|
254 |
iDataOffset = ( chunkBase + aRequiredLength + 3) & ~0x3;
|
|
255 |
|
|
256 |
return BlockAddress( iDataBlock ) + chunkBase;
|
|
257 |
}
|
|
258 |
|
|
259 |
|
|
260 |
|
|
261 |
inline TInt CBlockManager::BlockCount() const
|
|
262 |
{
|
|
263 |
return iBlockCount;
|
|
264 |
}
|
|
265 |
|
|
266 |
inline TInt CBlockManager::BlockSize() const
|
|
267 |
{
|
|
268 |
return iBlockSize;
|
|
269 |
}
|
|
270 |
|
|
271 |
inline TInt CBlockManager::FlashSize() const
|
|
272 |
{
|
|
273 |
return iBlockSize * iBlockCount;
|
|
274 |
}
|
|
275 |
|
|
276 |
inline TUint CBlockManager::BlockAddress( TInt aBlockNumber ) const
|
|
277 |
{
|
|
278 |
return (TUint)aBlockNumber * (TUint)iBlockSize;
|
|
279 |
}
|
|
280 |
|
|
281 |
|
|
282 |
// **********************************************************************
|
|
283 |
// Implementation of CWriteTest
|
|
284 |
|
|
285 |
CWriteTest::~CWriteTest()
|
|
286 |
{
|
|
287 |
if( iDriveOpened )
|
|
288 |
{
|
|
289 |
iDrive.Disconnect();
|
|
290 |
}
|
|
291 |
|
|
292 |
delete iBlocks;
|
|
293 |
delete iSimpleWriter;
|
|
294 |
delete iThreadWriter;
|
|
295 |
}
|
|
296 |
|
|
297 |
|
|
298 |
void CWriteTest::CreateL()
|
|
299 |
{
|
|
300 |
//
|
|
301 |
// Load the device drivers
|
|
302 |
//
|
|
303 |
TInt r;
|
|
304 |
#ifndef SKIP_PDD_LOAD
|
|
305 |
test.Printf( _L("Loading %S\n"), &KLfsDriverName );
|
|
306 |
r = User::LoadPhysicalDevice( KLfsDriverName );
|
|
307 |
test( KErrNone == r || KErrAlreadyExists == r );
|
|
308 |
#endif
|
|
309 |
|
|
310 |
#ifdef UNMOUNT_DRIVE
|
|
311 |
RFs fs;
|
|
312 |
test( KErrNone == fs.Connect() );
|
|
313 |
#if 0
|
|
314 |
// XXX - not EKA2
|
|
315 |
test( KErrNone == fs.SetDefaultPath( _L("Z:\\") ) );
|
|
316 |
#endif
|
|
317 |
TFullName name;
|
|
318 |
fs.FileSystemName( name, KLffsLogicalDriveNumber );
|
|
319 |
if( name.Length() > 0 )
|
|
320 |
{
|
|
321 |
test.Printf( _L("Unmounting drive") );
|
|
322 |
test( KErrNone == fs.DismountFileSystem( _L("Lffs"), KLffsLogicalDriveNumber) );
|
|
323 |
User::After( 2000000 );
|
|
324 |
test.Printf( _L("Drive unmounted") );
|
|
325 |
}
|
|
326 |
fs.Close();
|
|
327 |
#endif
|
|
328 |
|
|
329 |
//
|
|
330 |
// Open a TBusLogicalDevice to it
|
|
331 |
//
|
|
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;
|
|
337 |
|
|
338 |
//
|
|
339 |
// Initialise the block manager
|
|
340 |
//
|
|
341 |
iBlocks = new(ELeave) CBlockManager( iDrive, *this );
|
|
342 |
iBlocks->CreateL();
|
|
343 |
|
|
344 |
//
|
|
345 |
// Create a dummy thread that we can use to force
|
|
346 |
// other-thread write operations
|
|
347 |
//
|
|
348 |
#if 0
|
|
349 |
test( KErrNone == iDummyThread.Create( _L("DUMMY"), DummyThread, 256, KMinHeapSize, KMinHeapSize, NULL ) );
|
|
350 |
#else
|
|
351 |
test( KErrNone == iDummyThread.Create( _L("DUMMY"), DummyThread, KDefaultStackSize, KMinHeapSize, KMinHeapSize, NULL ) );
|
|
352 |
#endif
|
|
353 |
test.Printf( _L("Main thread handle=%d; dummy thread handle=%d"),
|
|
354 |
RThread().Handle(), DummyThreadHandle() );
|
|
355 |
|
|
356 |
//
|
|
357 |
// Create the writer classes
|
|
358 |
//
|
|
359 |
iSimpleWriter = new(ELeave) TSimpleWrite( *this );
|
|
360 |
iThreadWriter = new(ELeave) TThreadWrite( *this );
|
|
361 |
|
|
362 |
//
|
|
363 |
// Seed the pseudo-random number generator
|
|
364 |
//
|
|
365 |
iRandom.SetSeed( KRandomSeed1 );
|
|
366 |
|
|
367 |
|
|
368 |
test.Printf( _L("CWriteTest::CreateL complete\n") );
|
|
369 |
}
|
|
370 |
|
|
371 |
|
|
372 |
TInt CWriteTest::DummyThread( TAny* /* aParam */ )
|
|
373 |
//
|
|
374 |
// Thread does nothing at all
|
|
375 |
//
|
|
376 |
{
|
|
377 |
for(;;)
|
|
378 |
{
|
|
379 |
User::WaitForAnyRequest(); // just block
|
|
380 |
}
|
|
381 |
}
|
|
382 |
|
|
383 |
void CWriteTest::CreateRandomData( TDes8& aDestBuf, TInt aLength )
|
|
384 |
//
|
|
385 |
// Fills supplied descriptor with aLength bytes of pseudo-random test data
|
|
386 |
//
|
|
387 |
{
|
|
388 |
aDestBuf.SetLength( aLength );
|
|
389 |
TUint32* p = (TUint32*)aDestBuf.Ptr();
|
|
390 |
for( TInt j = aLength/4; j > 0 ; j-- )
|
|
391 |
{
|
|
392 |
*p++ = iRandom.Next();
|
|
393 |
}
|
|
394 |
|
|
395 |
if( aLength & 0x3 )
|
|
396 |
{
|
|
397 |
TUint8* q = (TUint8*)p;
|
|
398 |
for( TInt k = aLength & 3; k > 0; k-- )
|
|
399 |
{
|
|
400 |
*q++ = (TUint8)iRandom.Next();
|
|
401 |
}
|
|
402 |
}
|
|
403 |
}
|
|
404 |
|
|
405 |
|
|
406 |
TBool CWriteTest::CheckOnes( TUint aFlashOffset, TInt aLength )
|
|
407 |
//
|
|
408 |
// Checks that aLength bytes of data from offset aFlashOffset
|
|
409 |
// all contain 0xFF
|
|
410 |
//
|
|
411 |
{
|
|
412 |
TUint offset = aFlashOffset;
|
|
413 |
|
|
414 |
TBool failed = EFalse;
|
|
415 |
const TInt readBufLen = iReadBuffer.MaxLength();
|
|
416 |
|
|
417 |
for( TInt remaining = aLength; remaining > 0 && !failed ;)
|
|
418 |
{
|
|
419 |
TInt readLen = Min( remaining, readBufLen );
|
|
420 |
TInt r = iDrive.Read( offset, readLen, iReadBuffer );
|
|
421 |
if( r != KErrNone )
|
|
422 |
{
|
|
423 |
test.Printf( _L("... FAIL: read failed (%d) at offset 0x%x\n"), r, offset );
|
|
424 |
test( KErrNone == r );
|
|
425 |
}
|
|
426 |
test( iReadBuffer.Length() == readLen );
|
|
427 |
|
|
428 |
const TUint8* p = iReadBuffer.Ptr();
|
|
429 |
for( TInt i = 0; i < readLen; ++i )
|
|
430 |
{
|
|
431 |
if( 0xFF != *p )
|
|
432 |
{
|
|
433 |
failed = ETrue;
|
|
434 |
test.Printf( _L("... FAILED: byte @ offs=0x%x, read=0x%x, expected=0xFF\n"),
|
|
435 |
offset+i, p[0] );
|
|
436 |
break;
|
|
437 |
}
|
|
438 |
++p;
|
|
439 |
}
|
|
440 |
offset += readLen;
|
|
441 |
remaining -= readLen;
|
|
442 |
}
|
|
443 |
|
|
444 |
return !failed;
|
|
445 |
}
|
|
446 |
|
|
447 |
|
|
448 |
TBool CWriteTest::CompareAgainstFlash( TInt aFlashOffset, TInt aLength, const TDesC8& aDes, TInt aDescOffset )
|
|
449 |
//
|
|
450 |
// Checks that the data in aDes matches that in the Flash at position
|
|
451 |
// aFlashOffset.
|
|
452 |
// The test starts at offset aDescOffset in aSampleData. aLength bytes
|
|
453 |
// are tested.
|
|
454 |
//
|
|
455 |
{
|
|
456 |
__ASSERT_ALWAYS( aDescOffset + aLength <= aDes.Length(), Panic( EPanicCompareDescOverflow ) );
|
|
457 |
TInt dataLength = aLength;
|
|
458 |
const TUint8* srcPtr = aDes.Ptr() + aDescOffset;
|
|
459 |
|
|
460 |
TUint offset = aFlashOffset;
|
|
461 |
|
|
462 |
TBool failed = EFalse;
|
|
463 |
const TInt readBufLen = iReadBuffer.MaxLength();
|
|
464 |
|
|
465 |
while( (dataLength > 0) && !failed )
|
|
466 |
{
|
|
467 |
TInt len = Min( dataLength, readBufLen );
|
|
468 |
TInt r = iDrive.Read( offset, len, iReadBuffer );
|
|
469 |
if( r != KErrNone )
|
|
470 |
{
|
|
471 |
test.Printf( _L("... FAIL: read failed (%d) at offset 0x%x\n"), r, offset );
|
|
472 |
test( KErrNone == r );
|
|
473 |
}
|
|
474 |
test( iReadBuffer.Length() == len );
|
|
475 |
|
|
476 |
if( 0 != Mem::Compare( srcPtr, len, iReadBuffer.Ptr(), len ) )
|
|
477 |
{
|
|
478 |
test.Printf( _L("... FAIL: mismatch around offset 0x%x\n"), offset );
|
|
479 |
failed = ETrue;
|
|
480 |
}
|
|
481 |
offset += len;
|
|
482 |
dataLength -= len;
|
|
483 |
srcPtr += len;
|
|
484 |
}
|
|
485 |
|
|
486 |
return !failed;
|
|
487 |
}
|
|
488 |
|
|
489 |
TBool CWriteTest::CompareAgainstFlash( TInt aFlashOffset, const TDesC8& aDes )
|
|
490 |
//
|
|
491 |
// Checks that the data in aDes matches that in the Flash at position
|
|
492 |
// aFlashOffset.
|
|
493 |
// aDes->Length() bytes are tested.
|
|
494 |
//
|
|
495 |
{
|
|
496 |
return CompareAgainstFlash( aFlashOffset, aDes.Length(), aDes, 0 );
|
|
497 |
}
|
|
498 |
|
|
499 |
|
|
500 |
void CWriteTest::SimpleWriteTest()
|
|
501 |
{
|
|
502 |
test.Next( _L("Simple write test, simple write function") );
|
|
503 |
DoSimpleWriteTest( *iSimpleWriter );
|
|
504 |
}
|
|
505 |
|
|
506 |
void CWriteTest::SimpleThreadWriteTest()
|
|
507 |
{
|
|
508 |
test.Next( _L("Simple write test, thread write function") );
|
|
509 |
DoSimpleWriteTest( *iThreadWriter );
|
|
510 |
}
|
|
511 |
|
|
512 |
|
|
513 |
void CWriteTest::DoSimpleWriteTest( MGeneralizedWrite& aWriter )
|
|
514 |
//
|
|
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
|
|
517 |
//
|
|
518 |
{
|
|
519 |
TInt blockNo = iBlocks->NextErasedBlock();
|
|
520 |
TUint blockBase = iBlocks->BlockAddress( blockNo );
|
|
521 |
|
|
522 |
TBuf8<512> randomData;
|
|
523 |
CreateRandomData( randomData, randomData.MaxLength() );
|
|
524 |
|
|
525 |
TBuf8<512> randomDataDuplicate;
|
|
526 |
randomDataDuplicate.Copy( randomData );
|
|
527 |
test( randomDataDuplicate == randomData );
|
|
528 |
|
|
529 |
TBuf8<sizeof(TPtr)> ptrCopy; // used to take copies of descriptors
|
|
530 |
|
|
531 |
//
|
|
532 |
// Write using a constant descriptor TPtrC
|
|
533 |
//
|
|
534 |
test.Printf( _L("Write using TPtrC") );
|
|
535 |
TPtrC8 ptrC( randomData );
|
|
536 |
ptrCopy.Copy( (TUint8*)&ptrC, sizeof(ptrC) );
|
|
537 |
|
|
538 |
aWriter.CheckedWrite( blockBase + 0, ptrC );
|
|
539 |
|
|
540 |
test.Printf( _L("Check descriptor not modified by write function") );
|
|
541 |
test( 0 == Mem::Compare( (TUint8*)&ptrC, sizeof(ptrC), ptrCopy.Ptr(), sizeof(ptrC) ) );
|
|
542 |
|
|
543 |
test.Printf( _L("Check data not modified by write function") );
|
|
544 |
test( randomDataDuplicate == randomData );
|
|
545 |
|
|
546 |
//
|
|
547 |
// Write using a modifiable descriptor TPtr
|
|
548 |
//
|
|
549 |
test.Printf( _L("Write using TPtr") );
|
|
550 |
TPtr8 ptr( (TUint8*)randomData.Ptr(), randomData.Length(), randomData.Length() );
|
|
551 |
ptrCopy.Copy( (TUint8*)&ptr, sizeof(ptr) );
|
|
552 |
|
|
553 |
aWriter.CheckedWrite( blockBase + 1024, ptr );
|
|
554 |
|
|
555 |
test.Printf( _L("Check descriptor not modified by write function") );
|
|
556 |
test( 0 == Mem::Compare( (TUint8*)&ptr, sizeof(ptr), ptrCopy.Ptr(), sizeof(ptr) ) );
|
|
557 |
|
|
558 |
test.Printf( _L("Check data not modified by write function") );
|
|
559 |
test( randomDataDuplicate == randomData );
|
|
560 |
|
|
561 |
//
|
|
562 |
// Write using a modifiable descriptor TBuf
|
|
563 |
//
|
|
564 |
test.Printf( _L("Write using TBuf") );
|
|
565 |
|
|
566 |
aWriter.CheckedWrite( blockBase + 2048, randomData );
|
|
567 |
|
|
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() );
|
|
572 |
|
|
573 |
test.Printf( _L("Check data not modified by write function") );
|
|
574 |
test( randomDataDuplicate == randomData );
|
|
575 |
|
|
576 |
//
|
|
577 |
// Read the data back and check it matches
|
|
578 |
//
|
|
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 );
|
|
586 |
}
|
|
587 |
|
|
588 |
|
|
589 |
|
|
590 |
void CWriteTest::AlignedWriteTest()
|
|
591 |
{
|
|
592 |
test.Next( _L("Aligned write test, simple write function") );
|
|
593 |
DoAlignedWriteTest( *iSimpleWriter );
|
|
594 |
}
|
|
595 |
|
|
596 |
void CWriteTest::AlignedThreadWriteTest()
|
|
597 |
{
|
|
598 |
test.Next( _L("Aligned write test, thread write function") );
|
|
599 |
DoAlignedWriteTest( *iThreadWriter );
|
|
600 |
}
|
|
601 |
|
|
602 |
|
|
603 |
void CWriteTest::DoAlignedWriteTest( MGeneralizedWrite& aWriter )
|
|
604 |
//
|
|
605 |
// Writes data of various lengths to word-aligned addresses
|
|
606 |
//
|
|
607 |
{
|
|
608 |
iBlocks->InitialiseDataChunkAllocator();
|
|
609 |
|
|
610 |
TBuf8<512> data;
|
|
611 |
|
|
612 |
_LIT( KWriteMsg, " writing %d bytes @0x%x" );
|
|
613 |
|
|
614 |
test.Printf( _L("Testing small writes") );
|
|
615 |
|
|
616 |
for( TInt length = 1; length < 16; length++ )
|
|
617 |
{
|
|
618 |
CreateRandomData( data, length );
|
|
619 |
|
|
620 |
// get a 32-byte data chunk on a word boundary
|
|
621 |
TUint offset = iBlocks->NextErasedDataChunk( 32, 4 );
|
|
622 |
|
|
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 ) );
|
|
627 |
}
|
|
628 |
|
|
629 |
|
|
630 |
test.Printf( _L("Testing large writes") );
|
|
631 |
for( TInt length = 512-32; length <= 512 ; length++ )
|
|
632 |
{
|
|
633 |
CreateRandomData( data, length );
|
|
634 |
|
|
635 |
// get a 544-byte data chunk on a word boundary
|
|
636 |
TUint offset = iBlocks->NextErasedDataChunk( 544, 4 );
|
|
637 |
|
|
638 |
test.Printf( KWriteMsg, length, offset );
|
|
639 |
aWriter.CheckedWrite( offset, data );
|
|
640 |
|
|
641 |
// check that the section after the data still contains all ones
|
|
642 |
test( CheckOnes( offset + length, 544 - length ) );
|
|
643 |
}
|
|
644 |
}
|
|
645 |
|
|
646 |
|
|
647 |
|
|
648 |
|
|
649 |
void CWriteTest::UnalignedWriteTest()
|
|
650 |
{
|
|
651 |
test.Next( _L("Unaligned write test, simple write function") );
|
|
652 |
DoUnalignedWriteTest( *iSimpleWriter );
|
|
653 |
}
|
|
654 |
|
|
655 |
void CWriteTest::UnalignedThreadWriteTest()
|
|
656 |
{
|
|
657 |
test.Next( _L("Unaligned write test, thread write function") );
|
|
658 |
DoUnalignedWriteTest( *iThreadWriter );
|
|
659 |
}
|
|
660 |
|
|
661 |
|
|
662 |
void CWriteTest::DoUnalignedWriteTest( MGeneralizedWrite& aWriter )
|
|
663 |
//
|
|
664 |
// Tests writing to unaligned addresses. "Unaligned" here means
|
|
665 |
// addresses that are not on a word boundary.
|
|
666 |
//
|
|
667 |
{
|
|
668 |
TBuf8<32> data;
|
|
669 |
|
|
670 |
_LIT( KWriteMsg, " writing 32 bytes @0x%x" );
|
|
671 |
|
|
672 |
|
|
673 |
for( TInt offset = 1; offset < 32; offset++ )
|
|
674 |
{
|
|
675 |
CreateRandomData( data, data.MaxLength() );
|
|
676 |
|
|
677 |
//
|
|
678 |
// get a 64-byte data chunk on a 256-byte boundary, then
|
|
679 |
// start the write at <offset> bytes into this buffer
|
|
680 |
//
|
|
681 |
TUint dataChunk = iBlocks->NextErasedDataChunk( 64, 256 );
|
|
682 |
|
|
683 |
test.Printf( KWriteMsg, dataChunk + offset );
|
|
684 |
aWriter.CheckedWrite( dataChunk + offset, data );
|
|
685 |
|
|
686 |
_LIT( KBeforeMsg, " checking unused portion before data" );
|
|
687 |
test.Printf( KBeforeMsg );
|
|
688 |
test( CheckOnes( dataChunk, offset ) );
|
|
689 |
|
|
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() ) );
|
|
694 |
}
|
|
695 |
}
|
|
696 |
|
|
697 |
|
|
698 |
|
|
699 |
void CWriteTest::OffsetDescriptorAlignedWriteTest()
|
|
700 |
//
|
|
701 |
// Tests writing using an offset into the source data buffer. Writes
|
|
702 |
// are done to word-aligned destination addresses.
|
|
703 |
//
|
|
704 |
{
|
|
705 |
test.Next( _L("Offset-desc write test, aligned dest address") );
|
|
706 |
|
|
707 |
TBuf8<64> data;
|
|
708 |
|
|
709 |
_LIT( KWriteMsg, " writing 32 bytes from offset %d to @0x%x" );
|
|
710 |
|
|
711 |
// CreateRandomData( data, data.MaxLength() );
|
|
712 |
data.SetLength(64);
|
|
713 |
for( TInt i = 0; i < 64; i++ )
|
|
714 |
{
|
|
715 |
data[i] = i;
|
|
716 |
}
|
|
717 |
|
|
718 |
for( TInt descOffset = 1; descOffset < 32; descOffset++ )
|
|
719 |
{
|
|
720 |
//
|
|
721 |
// Get a 32-byte data chunk on a word boundary.
|
|
722 |
//
|
|
723 |
TUint dataChunk = iBlocks->NextErasedDataChunk( 32, 4 );
|
|
724 |
|
|
725 |
test.Printf( KWriteMsg, descOffset, dataChunk );
|
|
726 |
iThreadWriter->CheckedThreadWrite( dataChunk, 32, data, descOffset );
|
|
727 |
|
|
728 |
//
|
|
729 |
// Read the data back out and check it matches
|
|
730 |
//
|
|
731 |
_LIT( KReadBackMsg, "Reading back data" );
|
|
732 |
test.Printf( KReadBackMsg );
|
|
733 |
TBuf8<32> readData;
|
|
734 |
iDrive.Read( dataChunk, 32, readData );
|
|
735 |
TPtrC8 ptr( data.Ptr() + descOffset, 32 );
|
|
736 |
test( ptr == readData );
|
|
737 |
}
|
|
738 |
}
|
|
739 |
|
|
740 |
|
|
741 |
void CWriteTest::OffsetDescriptorUnalignedWriteTest()
|
|
742 |
//
|
|
743 |
// This is a variation of OffsetDescriptorAlignedWriteTest that
|
|
744 |
// also writes to non-word-aligned destionation addresses.
|
|
745 |
//
|
|
746 |
{
|
|
747 |
test.Next( _L("Offset-desc write test, unaligned dest address") );
|
|
748 |
|
|
749 |
TBuf8<64> data;
|
|
750 |
|
|
751 |
_LIT( KWriteMsg, " writing 32 bytes from offset %d to @0x%x" );
|
|
752 |
|
|
753 |
CreateRandomData( data, data.MaxLength() );
|
|
754 |
|
|
755 |
for( TInt descOffset = 1; descOffset < 32; descOffset++ )
|
|
756 |
{
|
|
757 |
for( TInt unalign = 1; unalign < 4; unalign++ )
|
|
758 |
{
|
|
759 |
//
|
|
760 |
// Get a 40-byte data chunk on a word boundary.
|
|
761 |
//
|
|
762 |
TUint dataChunk = iBlocks->NextErasedDataChunk( 40, 4 );
|
|
763 |
TUint destOffset = dataChunk + unalign;
|
|
764 |
|
|
765 |
test.Printf( KWriteMsg, descOffset, destOffset );
|
|
766 |
iThreadWriter->CheckedThreadWrite( destOffset, 32, data, descOffset );
|
|
767 |
|
|
768 |
//
|
|
769 |
// Read the data back out and check it matches
|
|
770 |
//
|
|
771 |
_LIT( KReadBackMsg, "Reading back data" );
|
|
772 |
test.Printf( KReadBackMsg );
|
|
773 |
TBuf8<32> readData;
|
|
774 |
iDrive.Read( destOffset, 32, readData );
|
|
775 |
TPtrC8 ptr( data.Ptr() + descOffset, 32 );
|
|
776 |
test( ptr == readData );
|
|
777 |
}
|
|
778 |
}
|
|
779 |
}
|
|
780 |
|
|
781 |
|
|
782 |
void CWriteTest::OffsetDescriptorCurrentThreadAlignedWriteTest()
|
|
783 |
//
|
|
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
|
|
787 |
// of this thread.
|
|
788 |
//
|
|
789 |
{
|
|
790 |
test.Next( _L("Offset-desc write test, current thread, aligned dest address") );
|
|
791 |
|
|
792 |
TBuf8<64> data;
|
|
793 |
|
|
794 |
_LIT( KWriteMsg, " writing 32 bytes from offset %d to @0x%x" );
|
|
795 |
|
|
796 |
// CreateRandomData( data, data.MaxLength() );
|
|
797 |
data.SetLength(64);
|
|
798 |
for( TInt i = 0; i < 64; i++ )
|
|
799 |
{
|
|
800 |
data[i] = i;
|
|
801 |
}
|
|
802 |
|
|
803 |
for( TInt descOffset = 1; descOffset < 32; descOffset++ )
|
|
804 |
{
|
|
805 |
//
|
|
806 |
// Get a 32-byte data chunk on a word boundary.
|
|
807 |
//
|
|
808 |
TUint dataChunk = iBlocks->NextErasedDataChunk( 32, 4 );
|
|
809 |
|
|
810 |
test.Printf( KWriteMsg, descOffset, dataChunk );
|
|
811 |
iThreadWriter->CurrentThreadCheckedThreadWrite( dataChunk, 32, data, descOffset );
|
|
812 |
|
|
813 |
//
|
|
814 |
// Read the data back out and check it matches
|
|
815 |
//
|
|
816 |
_LIT( KReadBackMsg, "Reading back data" );
|
|
817 |
test.Printf( KReadBackMsg );
|
|
818 |
TBuf8<32> readData;
|
|
819 |
iDrive.Read( dataChunk, 32, readData );
|
|
820 |
TPtrC8 ptr( data.Ptr() + descOffset, 32 );
|
|
821 |
test( ptr == readData );
|
|
822 |
}
|
|
823 |
}
|
|
824 |
|
|
825 |
|
|
826 |
void CWriteTest::OffsetDescriptorCurrentThreadUnalignedWriteTest()
|
|
827 |
//
|
|
828 |
// This is a variation of OffsetDescriptorCurrentThreadAlignedWriteTest
|
|
829 |
// that also writes to non-word-aligned destionation addresses.
|
|
830 |
//
|
|
831 |
{
|
|
832 |
test.Next( _L("Offset-desc write test, current thread, unaligned dest address") );
|
|
833 |
|
|
834 |
TBuf8<64> data;
|
|
835 |
|
|
836 |
_LIT( KWriteMsg, " writing 32 bytes from offset %d to @0x%x" );
|
|
837 |
|
|
838 |
CreateRandomData( data, data.MaxLength() );
|
|
839 |
|
|
840 |
for( TInt descOffset = 1; descOffset < 32; descOffset++ )
|
|
841 |
{
|
|
842 |
for( TInt unalign = 1; unalign < 4; unalign++ )
|
|
843 |
{
|
|
844 |
//
|
|
845 |
// Get a 40-byte data chunk on a word boundary.
|
|
846 |
//
|
|
847 |
TUint dataChunk = iBlocks->NextErasedDataChunk( 40, 4 );
|
|
848 |
TUint destOffset = dataChunk + unalign;
|
|
849 |
|
|
850 |
test.Printf( KWriteMsg, descOffset, destOffset );
|
|
851 |
iThreadWriter->CurrentThreadCheckedThreadWrite( destOffset, 32, data, descOffset );
|
|
852 |
|
|
853 |
//
|
|
854 |
// Read the data back out and check it matches
|
|
855 |
//
|
|
856 |
_LIT( KReadBackMsg, "Reading back data" );
|
|
857 |
test.Printf( KReadBackMsg );
|
|
858 |
TBuf8<32> readData;
|
|
859 |
iDrive.Read( destOffset, 32, readData );
|
|
860 |
TPtrC8 ptr( data.Ptr() + descOffset, 32 );
|
|
861 |
test( ptr == readData );
|
|
862 |
}
|
|
863 |
}
|
|
864 |
}
|
|
865 |
|
|
866 |
|
|
867 |
|
|
868 |
void CWriteTest::JoinedWriteTest()
|
|
869 |
//
|
|
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
|
|
873 |
// possible location
|
|
874 |
{
|
|
875 |
|
|
876 |
test.Next( _L("Joined write test, simple writes") );
|
|
877 |
|
|
878 |
//
|
|
879 |
// Reinitialise the chunk allocator
|
|
880 |
//
|
|
881 |
iBlocks->InitialiseDataChunkAllocator();
|
|
882 |
|
|
883 |
for( TInt join = 1; join < 63; join++ )
|
|
884 |
{
|
|
885 |
TBuf8<64> fullData;
|
|
886 |
CreateRandomData( fullData, fullData.MaxLength() );
|
|
887 |
|
|
888 |
//
|
|
889 |
// Create two TPtrC8s to the two parts of the data
|
|
890 |
//
|
|
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 ) );
|
|
894 |
|
|
895 |
//
|
|
896 |
// Get a location in the Flash to write to
|
|
897 |
//
|
|
898 |
TUint dataChunk = iBlocks->NextErasedDataChunk( 64, 64 );
|
|
899 |
|
|
900 |
//
|
|
901 |
// Write the two halves of the data
|
|
902 |
//
|
|
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 ) );
|
|
908 |
|
|
909 |
//
|
|
910 |
// Compare the data
|
|
911 |
//
|
|
912 |
_LIT( KCompareMsg, " comparing data against Flash" );
|
|
913 |
test.Printf( KCompareMsg );
|
|
914 |
test( CompareAgainstFlash( dataChunk, fullData ) );
|
|
915 |
}
|
|
916 |
}
|
|
917 |
|
|
918 |
|
|
919 |
void CWriteTest::JoinedThreadWriteTest()
|
|
920 |
//
|
|
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
|
|
924 |
// possible location
|
|
925 |
//
|
|
926 |
// This is similar to JoinedWriteTest except that the thread write
|
|
927 |
// function is used with a descriptor offset to chop up the
|
|
928 |
// source data
|
|
929 |
//
|
|
930 |
{
|
|
931 |
|
|
932 |
test.Next( _L("Joined write test, thread writes") );
|
|
933 |
|
|
934 |
//
|
|
935 |
// Reinitialise the chunk allocator
|
|
936 |
//
|
|
937 |
iBlocks->InitialiseDataChunkAllocator();
|
|
938 |
|
|
939 |
for( TInt join = 1; join < 63; join++ )
|
|
940 |
{
|
|
941 |
TBuf8<64> fullData;
|
|
942 |
CreateRandomData( fullData, fullData.MaxLength() );
|
|
943 |
|
|
944 |
//
|
|
945 |
// Get a location in the Flash to write to
|
|
946 |
//
|
|
947 |
TUint dataChunk = iBlocks->NextErasedDataChunk( 64, 64 );
|
|
948 |
|
|
949 |
//
|
|
950 |
// Write the two halves of the data
|
|
951 |
//
|
|
952 |
_LIT( KWriteMsg, " writing %d bytes @ 0x%x and %d bytes @ 0x%x" );
|
|
953 |
test.Printf( KWriteMsg, join, dataChunk, 64 - join, dataChunk + join );
|
|
954 |
#if 0
|
|
955 |
test( KErrNone == iDrive.Write( dataChunk, join, &fullData, DummyThreadHandle(), 0 ) );
|
|
956 |
test( KErrNone == iDrive.Write( dataChunk + join, 64-join, &fullData, DummyThreadHandle(), join ) );
|
|
957 |
#else
|
|
958 |
test( KErrNone == iDrive.Write( dataChunk, join, &fullData, KLocalMessageHandle, 0 ) );
|
|
959 |
test( KErrNone == iDrive.Write( dataChunk + join, 64-join, &fullData, KLocalMessageHandle, join ) );
|
|
960 |
#endif
|
|
961 |
|
|
962 |
|
|
963 |
//
|
|
964 |
// Compare the data
|
|
965 |
//
|
|
966 |
_LIT( KCompareMsg, " comparing data against Flash" );
|
|
967 |
test.Printf( KCompareMsg );
|
|
968 |
test( CompareAgainstFlash( dataChunk, fullData ) );
|
|
969 |
}
|
|
970 |
}
|
|
971 |
|
|
972 |
|
|
973 |
|
|
974 |
void CWriteTest::SingleBitOverwriteTest()
|
|
975 |
//
|
|
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
|
|
979 |
// is verified.
|
|
980 |
//
|
|
981 |
{
|
|
982 |
test.Next( _L("Single bit overwrite test") );
|
|
983 |
|
|
984 |
iBlocks->InitialiseDataChunkAllocator();
|
|
985 |
|
|
986 |
for( TInt testByteOffset = 0; testByteOffset < 32; testByteOffset++ )
|
|
987 |
{
|
|
988 |
for( TInt testBitNumber = 0; testBitNumber < 8; testBitNumber++ )
|
|
989 |
{
|
|
990 |
TBuf8<32> data;
|
|
991 |
CreateRandomData( data, data.MaxLength() );
|
|
992 |
data[ testByteOffset ] = 0xFF; // force test byte to 0xFF
|
|
993 |
|
|
994 |
TUint flashOffset = iBlocks->NextErasedDataChunk( 32, 32 );
|
|
995 |
|
|
996 |
_LIT( KWriteMsg, "writing test data @0x%x, test byte offset=%d; test bit #%d");
|
|
997 |
test.Printf( KWriteMsg, flashOffset, testByteOffset, testBitNumber );
|
|
998 |
|
|
999 |
iSimpleWriter->CheckedWrite( flashOffset, data );
|
|
1000 |
|
|
1001 |
// clear the test bit
|
|
1002 |
TBuf8<1> byte;
|
|
1003 |
byte.SetLength(1);
|
|
1004 |
byte[0] = ~(1 << testBitNumber);
|
|
1005 |
data[ testByteOffset ] = byte[0];
|
|
1006 |
|
|
1007 |
iSimpleWriter->CheckedWrite( flashOffset + testByteOffset, byte );
|
|
1008 |
|
|
1009 |
// check that the contents of the Flash matches the buffer
|
|
1010 |
test( CompareAgainstFlash( flashOffset, data ) );
|
|
1011 |
}
|
|
1012 |
}
|
|
1013 |
}
|
|
1014 |
|
|
1015 |
void CWriteTest::TwoBitOverwriteTest()
|
|
1016 |
//
|
|
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
|
|
1020 |
// is verified.
|
|
1021 |
//
|
|
1022 |
{
|
|
1023 |
static const TUint pattConv[16] =
|
|
1024 |
{
|
|
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
|
|
1028 |
};
|
|
1029 |
test.Next( _L("Two bit overwrite test") );
|
|
1030 |
|
|
1031 |
for( TInt testByteOffset = 0; testByteOffset < 32; testByteOffset++ )
|
|
1032 |
{
|
|
1033 |
for( TInt testBitJ = 0; testBitJ < 7; testBitJ++ )
|
|
1034 |
{
|
|
1035 |
for( TInt testBitK = testBitJ+1; testBitK < 8; testBitK++ )
|
|
1036 |
{
|
|
1037 |
TBuf8<32> data;
|
|
1038 |
CreateRandomData( data, data.MaxLength() );
|
|
1039 |
data[ testByteOffset ] = 0xFF; // force test byte to 0xFF
|
|
1040 |
|
|
1041 |
TUint flashOffset = iBlocks->NextErasedDataChunk( 32, 32 );
|
|
1042 |
|
|
1043 |
TUint8 testPattern = ~((1 << testBitJ) | (1 << testBitK));
|
|
1044 |
|
|
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 ] );
|
|
1048 |
|
|
1049 |
iSimpleWriter->CheckedWrite( flashOffset, data );
|
|
1050 |
|
|
1051 |
TBuf8<1> byte;
|
|
1052 |
byte.SetLength(1);
|
|
1053 |
byte[0] = testPattern;
|
|
1054 |
data[ testByteOffset ] = testPattern;
|
|
1055 |
|
|
1056 |
iSimpleWriter->CheckedWrite( flashOffset + testByteOffset, byte );
|
|
1057 |
|
|
1058 |
// check that the contents of the Flash matches the buffer
|
|
1059 |
test( CompareAgainstFlash( flashOffset, data ) );
|
|
1060 |
}
|
|
1061 |
}
|
|
1062 |
}
|
|
1063 |
}
|
|
1064 |
|
|
1065 |
|
|
1066 |
void CWriteTest::RunSimulationTest()
|
|
1067 |
//
|
|
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.
|
|
1071 |
//
|
|
1072 |
{
|
|
1073 |
test.Next( _L("Simulation test") );
|
|
1074 |
|
|
1075 |
TUint blockBase = iBlocks->BlockAddress( iBlocks->NextErasedBlock() );
|
|
1076 |
|
|
1077 |
TUint lowAddress = blockBase;
|
|
1078 |
TUint highAddress = blockBase + iBlocks->BlockSize() - 512;
|
|
1079 |
|
|
1080 |
TBuf8<24> lowData;
|
|
1081 |
TBuf8<512> highData;
|
|
1082 |
TPtrC8 overwritePtr( lowData.Ptr(), 1 );
|
|
1083 |
|
|
1084 |
while( lowAddress + 24 < highAddress )
|
|
1085 |
{
|
|
1086 |
CreateRandomData( lowData, lowData.MaxLength() );
|
|
1087 |
CreateRandomData( highData, highData.MaxLength() );
|
|
1088 |
lowData[0] = 0xE7; // just some non-0xFF value
|
|
1089 |
|
|
1090 |
_LIT( KWriteMsg, "Writing block size 24 @ 0x%x; block size 512 @ 0x%x" );
|
|
1091 |
test.Printf( KWriteMsg, lowAddress, highAddress );
|
|
1092 |
|
|
1093 |
iSimpleWriter->CheckedWrite( lowAddress, lowData );
|
|
1094 |
iSimpleWriter->Write( highAddress, highData );
|
|
1095 |
|
|
1096 |
// Overwrite the byte
|
|
1097 |
lowData[0] = 0xA7;
|
|
1098 |
iSimpleWriter->Write( lowAddress, overwritePtr );
|
|
1099 |
|
|
1100 |
test( CompareAgainstFlash( lowAddress, lowData ) );
|
|
1101 |
test( CompareAgainstFlash( highAddress, highData ) );
|
|
1102 |
|
|
1103 |
lowAddress += lowData.Length();
|
|
1104 |
highAddress -= highData.Length();
|
|
1105 |
}
|
|
1106 |
}
|
|
1107 |
|
|
1108 |
|
|
1109 |
|
|
1110 |
void CWriteTest::DoTests()
|
|
1111 |
//
|
|
1112 |
// Main test dispatcher
|
|
1113 |
//
|
|
1114 |
{
|
|
1115 |
test.Next( _L("Erasing all blocks") );
|
|
1116 |
iBlocks->InitialiseSequentialBlockAllocator();
|
|
1117 |
iBlocks->EraseAllBlocks();
|
|
1118 |
|
|
1119 |
//
|
|
1120 |
// Basic tests that we can write data correctly without corrupting
|
|
1121 |
// the source buffer
|
|
1122 |
//
|
|
1123 |
SimpleWriteTest();
|
|
1124 |
SimpleThreadWriteTest();
|
|
1125 |
|
|
1126 |
//
|
|
1127 |
// Test aligned writes of various lengths
|
|
1128 |
//
|
|
1129 |
AlignedWriteTest();
|
|
1130 |
AlignedThreadWriteTest();
|
|
1131 |
|
|
1132 |
//
|
|
1133 |
// Test writing to unaligned locations
|
|
1134 |
//
|
|
1135 |
UnalignedWriteTest();
|
|
1136 |
UnalignedThreadWriteTest();
|
|
1137 |
|
|
1138 |
//
|
|
1139 |
// Test writes with offset into source desriptor
|
|
1140 |
//
|
|
1141 |
OffsetDescriptorCurrentThreadAlignedWriteTest();
|
|
1142 |
OffsetDescriptorCurrentThreadUnalignedWriteTest();
|
|
1143 |
OffsetDescriptorAlignedWriteTest();
|
|
1144 |
OffsetDescriptorUnalignedWriteTest();
|
|
1145 |
|
|
1146 |
//
|
|
1147 |
// Test two consecutive writes
|
|
1148 |
//
|
|
1149 |
JoinedWriteTest();
|
|
1150 |
JoinedThreadWriteTest();
|
|
1151 |
|
|
1152 |
//
|
|
1153 |
// Test that we can overwrite bits
|
|
1154 |
//
|
|
1155 |
SingleBitOverwriteTest();
|
|
1156 |
TwoBitOverwriteTest();
|
|
1157 |
|
|
1158 |
//
|
|
1159 |
// A simulation test of LFFS usage
|
|
1160 |
//
|
|
1161 |
RunSimulationTest();
|
|
1162 |
}
|
|
1163 |
|
|
1164 |
|
|
1165 |
|
|
1166 |
|
|
1167 |
|
|
1168 |
|
|
1169 |
|
|
1170 |
|
|
1171 |
|
|
1172 |
|
|
1173 |
TInt E32Main()
|
|
1174 |
{
|
|
1175 |
test.Title();
|
|
1176 |
test.Start(_L("Testing media read operations"));
|
|
1177 |
|
|
1178 |
CWriteTest writeTest;
|
|
1179 |
TRAPD( ret, writeTest.CreateL() );
|
|
1180 |
test( KErrNone == ret );
|
|
1181 |
writeTest.DoTests();
|
|
1182 |
test.End();
|
|
1183 |
|
|
1184 |
return 0;
|
|
1185 |
}
|