|
1 // Copyright (c) 2000-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 |
|
23 RTest test( _L("TF_READ") ); |
|
24 |
|
25 |
|
26 const TInt KTestUserDataSize = 1024; |
|
27 const TInt KBufferGuardSize = 16384; |
|
28 |
|
29 const TInt KMaxWriteLength = 512; |
|
30 |
|
31 const TInt64 KSampleDataRandomSeed = MAKE_TINT64(0x3e000111,0xAFCBDF0F); |
|
32 const TInt64 KRandomTestSeed = MAKE_TINT64(0x90009901,0xABEF1011); |
|
33 |
|
34 enum TPanicNo |
|
35 { |
|
36 EPanicGetDesOverflow, |
|
37 EPanicGetDesInitialOverflow, |
|
38 EPanicCheckOverflow |
|
39 }; |
|
40 |
|
41 LOCAL_D void Panic( TPanicNo aPanic ) |
|
42 { |
|
43 _LIT( KPanicCat, "TF_READ" ); |
|
44 User::Panic( KPanicCat, aPanic ); |
|
45 } |
|
46 |
|
47 |
|
48 class CCheckedBuffer : public CBase |
|
49 { |
|
50 public: |
|
51 CCheckedBuffer( TInt auserDataSize, TInt aGuardSize ); |
|
52 ~CCheckedBuffer(); |
|
53 |
|
54 void CreateL(); |
|
55 void InitialiseGuard(); |
|
56 TBool CheckGuard( TInt aUserDataLength ) const; |
|
57 TBool CheckGuardAtStartOfUserData( TInt aGuardLength ) const; |
|
58 void GetDes( TPtrC8& aDes ) const; |
|
59 void GetDes( TPtr8& aDes, TInt aInitialLength, TInt aMaxLength ) const; |
|
60 |
|
61 |
|
62 private: |
|
63 CCheckedBuffer(); |
|
64 |
|
65 private: |
|
66 TPtr8 iUserData; // pointer to user data area |
|
67 const TInt iUserDataSize; |
|
68 const TInt iGuardSize; |
|
69 TUint8* iAllocCell; |
|
70 }; |
|
71 |
|
72 |
|
73 |
|
74 CCheckedBuffer::CCheckedBuffer( TInt aUserDataSize, TInt aGuardSize ) |
|
75 : iUserData(0,0), iUserDataSize( aUserDataSize ), iGuardSize( aGuardSize ) |
|
76 { |
|
77 } |
|
78 |
|
79 CCheckedBuffer::~CCheckedBuffer() |
|
80 { |
|
81 delete iAllocCell; |
|
82 } |
|
83 |
|
84 void CCheckedBuffer::CreateL() |
|
85 { |
|
86 TInt totalCellSizeRequired = iUserDataSize + (2 * iGuardSize); |
|
87 |
|
88 iAllocCell = (TUint8*)User::AllocL( totalCellSizeRequired ); |
|
89 |
|
90 test.Printf( _L("Allocated heap cell for checked buffer\n") ); |
|
91 |
|
92 iUserData.Set( iAllocCell + iGuardSize, iUserDataSize, iUserDataSize ); |
|
93 } |
|
94 |
|
95 void CCheckedBuffer::GetDes( TPtrC8& aDes ) const |
|
96 // |
|
97 // Create descriptor to the whole user data area in aDes |
|
98 // |
|
99 { |
|
100 aDes.Set( iAllocCell + iGuardSize, iUserDataSize ); |
|
101 } |
|
102 |
|
103 void CCheckedBuffer::GetDes( TPtr8& aDes, TInt aInitialLength, TInt aMaxLength ) const |
|
104 // |
|
105 // Create modifiable descriptor to the user data area in aDes, |
|
106 // with a maximum length aMaxLength, and initial length aInitialLength |
|
107 // |
|
108 { |
|
109 __ASSERT_ALWAYS( aMaxLength <= iUserDataSize, Panic(EPanicGetDesOverflow) ); |
|
110 __ASSERT_ALWAYS( aInitialLength <= iUserDataSize, Panic(EPanicGetDesInitialOverflow) ); |
|
111 aDes.Set( iAllocCell + iGuardSize, aInitialLength, aMaxLength ); |
|
112 } |
|
113 |
|
114 |
|
115 void CCheckedBuffer::InitialiseGuard() |
|
116 // |
|
117 // Create the guard regions |
|
118 // |
|
119 { |
|
120 TInt totalCellSize = User::AllocLen( iAllocCell ); |
|
121 Mem::Fill( iAllocCell, totalCellSize, 0x5A ); |
|
122 } |
|
123 |
|
124 TBool CCheckedBuffer::CheckGuard( TInt aUserDataLength ) const |
|
125 // |
|
126 // Checks that the guard value is still present before the user data |
|
127 // area, and after aUserDataLength bytes of user data |
|
128 // |
|
129 { |
|
130 const TUint8* p = iAllocCell; |
|
131 const TUint8* pUserDataStart = iUserData.Ptr(); |
|
132 |
|
133 for( ; p < pUserDataStart; p++ ) |
|
134 { |
|
135 if( 0x5a != *p ) |
|
136 { |
|
137 return EFalse; |
|
138 } |
|
139 } |
|
140 |
|
141 p = pUserDataStart + aUserDataLength; |
|
142 const TUint8* pEnd = iAllocCell + User::AllocLen( iAllocCell ); |
|
143 |
|
144 for( ; p < pEnd; p++ ) |
|
145 { |
|
146 if( 0x5a != *p ) |
|
147 { |
|
148 return EFalse; |
|
149 } |
|
150 } |
|
151 |
|
152 return ETrue; |
|
153 } |
|
154 |
|
155 |
|
156 TBool CCheckedBuffer::CheckGuardAtStartOfUserData( TInt aGuardLength ) const |
|
157 // |
|
158 // Checks that the first aGuardLength bytes of the user data area |
|
159 // contain the guard value |
|
160 // |
|
161 { |
|
162 const TUint8* p = iUserData.Ptr(); |
|
163 const TUint8* pEnd = p + aGuardLength; |
|
164 |
|
165 for( ; p < pEnd; p++ ) |
|
166 { |
|
167 if( 0x5a != *p ) |
|
168 { |
|
169 return EFalse; |
|
170 } |
|
171 } |
|
172 |
|
173 return ETrue; |
|
174 } |
|
175 |
|
176 |
|
177 |
|
178 class CReadTest : public CBase |
|
179 { |
|
180 public: |
|
181 ~CReadTest(); |
|
182 |
|
183 void CreateL(); |
|
184 |
|
185 void DoTest(); |
|
186 |
|
187 private: |
|
188 static TInt DummyThread( TAny* aParam ); |
|
189 |
|
190 void CreateSampleData(); |
|
191 static TBool CheckZero( const TPtrC8& aDes ); |
|
192 void CreateTestData( TInt aBlockNumber, TBool aEndOfBlock ); |
|
193 TBool CompareAgainstFlash( TInt aFlashOffset, const TPtrC8& aDes, TInt aDescOffset ); |
|
194 |
|
195 void TestSimpleReads(); |
|
196 void TestSimpleThreadReads(); |
|
197 void TestUnalignedReads(); |
|
198 void TestUnalignedThreadReads(); |
|
199 void TestOffsetBufferThreadReads(); |
|
200 void TestOffsetBufferUnalignedThreadReads(); |
|
201 void TestReadsFromAllBlocks(); |
|
202 void TestSimpleScatterReads1(); |
|
203 void TestSimpleScatterReads2(); |
|
204 void TestScatterGather(); |
|
205 void TestReadAcrossBlock(); |
|
206 |
|
207 void PerformCheckedRead( TInt aReadPos, TInt aReadLen ); |
|
208 void PerformCheckedThreadRead( TInt aReadPos, TInt aReadLen, TInt aDescOffset ); |
|
209 |
|
210 private: |
|
211 TInt iFlashSize; |
|
212 TInt iBlockSize; |
|
213 TInt iBlockCount; |
|
214 |
|
215 TBusLocalDrive iDrive; |
|
216 TBool iDriveOpened; |
|
217 TBuf8<512> iReadBuffer; |
|
218 |
|
219 TRandomGenerator iRandom; |
|
220 |
|
221 TBuf8<KTestUserDataSize> iSampleData; |
|
222 |
|
223 CCheckedBuffer* iBuffer; |
|
224 |
|
225 RThread iDummyThread; |
|
226 }; |
|
227 |
|
228 CReadTest::~CReadTest() |
|
229 { |
|
230 if( iDriveOpened ) |
|
231 { |
|
232 iDrive.Disconnect(); |
|
233 } |
|
234 } |
|
235 |
|
236 |
|
237 |
|
238 void CReadTest::CreateL() |
|
239 { |
|
240 // |
|
241 // Load the device drivers |
|
242 // |
|
243 TInt r; |
|
244 |
|
245 #ifndef SKIP_PDD_LOAD |
|
246 test.Printf( _L("Loading %S\n"), &KLfsDriverName ); |
|
247 r = User::LoadPhysicalDevice( KLfsDriverName ); |
|
248 test( KErrNone == r || KErrAlreadyExists == r ); |
|
249 #endif |
|
250 |
|
251 #ifdef UNMOUNT_DRIVE |
|
252 RFs fs; |
|
253 test( KErrNone == fs.Connect() ); |
|
254 #if 0 // XXX - API violation on EKA2 |
|
255 test( KErrNone == fs.SetDefaultPath( _L("Z:\\") ) ); |
|
256 #endif |
|
257 TFullName name; |
|
258 fs.FileSystemName( name, KLffsLogicalDriveNumber ); |
|
259 if( name.Length() > 0 ) |
|
260 { |
|
261 test.Printf( _L("Unmounting drive") ); |
|
262 test( KErrNone == fs.DismountFileSystem( _L("Lffs"), KLffsLogicalDriveNumber) ); |
|
263 User::After( 2000000 ); |
|
264 test.Printf( _L("Drive unmounted") ); |
|
265 } |
|
266 |
|
267 fs.Close(); |
|
268 #endif |
|
269 |
|
270 // |
|
271 // Open a TBusLogicalDevice to it |
|
272 // |
|
273 test.Printf( _L("Opening media channel\n") ); |
|
274 TBool changedFlag = EFalse; |
|
275 r = iDrive.Connect( KDriveNumber, changedFlag ); |
|
276 User::LeaveIfError( r ); |
|
277 iDriveOpened = ETrue; |
|
278 |
|
279 // |
|
280 // Get size of Flash drive |
|
281 // |
|
282 TLocalDriveCapsV2Buf info; |
|
283 iDrive.Caps(info); |
|
284 iFlashSize = I64LOW(info().iSize); |
|
285 iBlockSize = info().iEraseBlockSize; |
|
286 iBlockCount = iFlashSize / iBlockSize; |
|
287 |
|
288 test.Printf( _L("Flash size is 0x%x bytes\n"), iFlashSize ); |
|
289 |
|
290 // |
|
291 // Create a dummy thread that we can use to force |
|
292 // other-thread write operations |
|
293 // |
|
294 #if 0 |
|
295 test( KErrNone == iDummyThread.Create( _L("DUMMY"), DummyThread, 256, KMinHeapSize, KMinHeapSize, NULL ) ); |
|
296 #else |
|
297 // XXX TONYL |
|
298 test( KErrNone == iDummyThread.Create( _L("DUMMY"), DummyThread, KDefaultStackSize, KMinHeapSize, KMinHeapSize, NULL ) ); |
|
299 |
|
300 // test.Printf( _L("== do it")); |
|
301 // TInt pas = iDummyThread.Create( _L("DUMMY"), DummyThread, KDefaultStackSize, KMinHeapSize, KMinHeapSize, NULL ); |
|
302 // test.Printf( _L("CREATE = %d"), pas); |
|
303 // test (pas == KErrNone); |
|
304 #endif |
|
305 #if 1 |
|
306 iDummyThread.Resume(); |
|
307 #endif |
|
308 |
|
309 // |
|
310 // Create a checked buffer |
|
311 // |
|
312 iBuffer = new(ELeave) CCheckedBuffer( KTestUserDataSize, KBufferGuardSize ); |
|
313 iBuffer->CreateL(); |
|
314 |
|
315 // |
|
316 // Seed the pseudo-random number generator |
|
317 // |
|
318 iRandom.SetSeed( KSampleDataRandomSeed ); |
|
319 |
|
320 test.Printf( _L("CreateL complete\n") ); |
|
321 } |
|
322 |
|
323 |
|
324 |
|
325 TInt CReadTest::DummyThread( TAny* /* aParam */ ) |
|
326 // |
|
327 // Thread does nothing at all |
|
328 // |
|
329 { |
|
330 #if 1 |
|
331 test.Printf( _L("== do it")); |
|
332 #endif |
|
333 for(;;) |
|
334 { |
|
335 User::WaitForAnyRequest(); // just block |
|
336 } |
|
337 } |
|
338 |
|
339 |
|
340 void CReadTest::TestSimpleReads() |
|
341 // |
|
342 // Makes reads of 1 byte to 512 bytes into the start of the |
|
343 // checked buffer and tests that only the expected bytes have changed |
|
344 // This uses the simple read function from TBusLocalDrive, and |
|
345 // reads from an aligned Flash address |
|
346 // |
|
347 { |
|
348 test.Next( _L("Testing simple reads\n") ); |
|
349 |
|
350 // |
|
351 // Descriptor to user data area, passed to media driver |
|
352 // |
|
353 TPtr8 des(0,0); |
|
354 |
|
355 for( TInt readLen = 1; readLen <= 512; readLen++ ) |
|
356 { |
|
357 test.Printf( _L("Reading %d bytes\n"), readLen ); |
|
358 |
|
359 // |
|
360 // Prepare the guard data |
|
361 // |
|
362 iBuffer->InitialiseGuard(); |
|
363 |
|
364 // |
|
365 // Set up the descriptor, length=0, maxlen=readLen |
|
366 // |
|
367 iBuffer->GetDes( des, 0, readLen ); |
|
368 |
|
369 // |
|
370 // Now read some data into it |
|
371 // |
|
372 test( KErrNone == iDrive.Read( 0, readLen, des ) ); |
|
373 |
|
374 // |
|
375 // Check what we got |
|
376 // |
|
377 test( des.Length() == readLen ); |
|
378 |
|
379 TPtrC8 newDes; |
|
380 |
|
381 iBuffer->GetDes( newDes ); |
|
382 |
|
383 test( newDes.Ptr() == des.Ptr() ); |
|
384 |
|
385 test( iBuffer->CheckGuard( readLen ) ); |
|
386 |
|
387 test( CompareAgainstFlash( 0, des, 0 ) ); |
|
388 |
|
389 } |
|
390 } |
|
391 |
|
392 void CReadTest::TestSimpleThreadReads() |
|
393 // |
|
394 // Makes reads of 1 byte to 512 bytes into the start of the |
|
395 // checked buffer and tests that only the expected bytes have changed |
|
396 // This uses the more complex read function from TBusLocalDrive, and |
|
397 // reads from an aligned Flash address |
|
398 // |
|
399 { |
|
400 test.Next( _L("Testing simple reads using other-thread read function\n") ); |
|
401 |
|
402 // |
|
403 // Descriptor to user data area, passed to media driver |
|
404 // |
|
405 TPtr8 des(0,0); |
|
406 |
|
407 for( TInt readLen = 1; readLen <= 512; readLen++ ) |
|
408 { |
|
409 test.Printf( _L("Reading %d bytes\n"), readLen ); |
|
410 |
|
411 // |
|
412 // Prepare the guard data |
|
413 // |
|
414 iBuffer->InitialiseGuard(); |
|
415 test.Printf( _L("AA\n")); |
|
416 |
|
417 // |
|
418 // Set up the descriptor, length=0, maxlen=readLen |
|
419 // |
|
420 iBuffer->GetDes( des, 0, readLen ); |
|
421 test.Printf( _L("BB\n")); |
|
422 |
|
423 // |
|
424 // Now read some data into it |
|
425 // |
|
426 test( KErrNone == iDrive.Read( 0, readLen, &des, KLocalMessageHandle, 0 ) ); |
|
427 test.Printf( _L("CC\n")); |
|
428 #if 0 |
|
429 test( KErrNone == iDrive.Read( 0, readLen, &des, iDummyThread.Handle(), 0 ) ); |
|
430 #else |
|
431 // XXX - this works |
|
432 test( KErrNone == iDrive.Read( 0, readLen, &des, KLocalMessageHandle, 0 ) ); |
|
433 #endif |
|
434 |
|
435 // |
|
436 // Check what we got |
|
437 // |
|
438 test.Printf( _L("DD\n")); |
|
439 test.Printf( _L("DD\n")); |
|
440 test.Printf( _L("DD\n")); |
|
441 test.Printf( _L("DD\n")); |
|
442 test( des.Length() == readLen ); |
|
443 |
|
444 TPtrC8 newDes; |
|
445 test.Printf( _L("EE\n")); |
|
446 iBuffer->GetDes( newDes ); |
|
447 test.Printf( _L("FF\n")); |
|
448 test( newDes.Ptr() == des.Ptr() ); |
|
449 |
|
450 test( iBuffer->CheckGuard( readLen ) ); |
|
451 |
|
452 test.Printf( _L("GG\n")); |
|
453 test( CompareAgainstFlash( 0, des, 0 ) ); |
|
454 test.Printf( _L("HH\n")); |
|
455 |
|
456 } |
|
457 } |
|
458 |
|
459 |
|
460 void CReadTest::TestUnalignedReads() |
|
461 // |
|
462 // Makes reads of 1 byte to 512 bytes into the start of the |
|
463 // checked buffer and tests that only the expected bytes have changed |
|
464 // This uses the simple read function from TBusLocalDrive. |
|
465 // The data is read from an unaligned address (0ffset 1, 2, 3) |
|
466 // |
|
467 { |
|
468 test.Next( _L("Testing unaligned reads\n") ); |
|
469 |
|
470 // |
|
471 // Descriptor to user data area, passed to media driver |
|
472 // |
|
473 TPtr8 des(0,0); |
|
474 |
|
475 for( TInt readLen = 1; readLen <= 512; readLen++ ) |
|
476 { |
|
477 // |
|
478 // Set up the descriptor, length=0, maxlen=readLen |
|
479 // |
|
480 iBuffer->GetDes( des, 0, readLen ); |
|
481 |
|
482 // |
|
483 // Repeat for each offset |
|
484 // |
|
485 for( TInt offs = 1; offs < 4; offs++ ) |
|
486 { |
|
487 test.Printf( _L("Reading %d unaligned bytes from offset %d\n"), readLen, offs ); |
|
488 |
|
489 iBuffer->InitialiseGuard(); |
|
490 test( KErrNone == iDrive.Read( offs, readLen, des ) ); |
|
491 |
|
492 test( des.Length() == readLen ); |
|
493 |
|
494 TPtrC8 newDes; |
|
495 iBuffer->GetDes( newDes ); |
|
496 test( newDes.Ptr() == des.Ptr() ); |
|
497 |
|
498 test( iBuffer->CheckGuard( readLen ) ); |
|
499 |
|
500 test( CompareAgainstFlash( offs, des, 0 ) ); |
|
501 } |
|
502 |
|
503 } |
|
504 } |
|
505 |
|
506 |
|
507 void CReadTest::TestUnalignedThreadReads() |
|
508 // |
|
509 // Makes reads of 1 byte to 512 bytes into the start of the |
|
510 // checked buffer and tests that only the expected bytes have changed |
|
511 // This uses the thread read function from TBusLocalDrive. |
|
512 // The data is read from an unaligned address (0ffset 1, 2, 3) |
|
513 // |
|
514 { |
|
515 test.Next( _L("Testing unaligned other-thread reads\n") ); |
|
516 |
|
517 // |
|
518 // Descriptor to user data area, passed to media driver |
|
519 // |
|
520 TPtr8 des(0,0); |
|
521 |
|
522 for( TInt readLen = 1; readLen <= 512; readLen++ ) |
|
523 { |
|
524 // |
|
525 // Set up the descriptor, length=0, maxlen=readLen |
|
526 // |
|
527 iBuffer->GetDes( des, 0, readLen ); |
|
528 |
|
529 // |
|
530 // Repeat for each offset |
|
531 // |
|
532 for( TInt offs = 1; offs < 4; offs++ ) |
|
533 { |
|
534 test.Printf( _L("Reading %d unaligned bytes from offset %d\n"), readLen, offs ); |
|
535 |
|
536 iBuffer->InitialiseGuard(); |
|
537 #if 0 |
|
538 test( KErrNone == iDrive.Read( offs, readLen, &des, iDummyThread.Handle(), 0 ) ); |
|
539 #else |
|
540 test( KErrNone == iDrive.Read( offs, readLen, &des, KLocalMessageHandle, 0 ) ); |
|
541 #endif |
|
542 |
|
543 test( des.Length() == readLen ); |
|
544 |
|
545 TPtrC8 newDes; |
|
546 iBuffer->GetDes( newDes ); |
|
547 test( newDes.Ptr() == des.Ptr() ); |
|
548 |
|
549 test( iBuffer->CheckGuard( readLen ) ); |
|
550 |
|
551 test( CompareAgainstFlash( offs, des, 0 ) ); |
|
552 } |
|
553 |
|
554 } |
|
555 } |
|
556 |
|
557 |
|
558 void CReadTest::TestOffsetBufferThreadReads() |
|
559 // |
|
560 // Makes reads of 1 byte to 512 bytes to an offset position in the |
|
561 // checked buffer and tests that only the expected bytes have changed |
|
562 // This uses the more complex read function from TBusLocalDrive, and |
|
563 // reads from an aligned Flash address |
|
564 // |
|
565 { |
|
566 test.Next( _L("Testing other-thread reads into offset position in descriptor\n") ); |
|
567 |
|
568 // |
|
569 // Descriptor to user data area, passed to media driver |
|
570 // |
|
571 TPtr8 des(0,0); |
|
572 |
|
573 for( TInt readLen = 1; readLen <= 512; readLen++ ) |
|
574 { |
|
575 test.Printf( _L("Reading %d bytes\n"), readLen ); |
|
576 |
|
577 |
|
578 // |
|
579 // Repeat test for offsets 0..64 in buffer |
|
580 // |
|
581 for( TInt destOffset = 1; destOffset < 64; destOffset++ ) |
|
582 { |
|
583 // test.Printf( _L("... dest offset = %d"), destOffset ); |
|
584 |
|
585 // |
|
586 // Prepare the guard data |
|
587 // |
|
588 iBuffer->InitialiseGuard(); |
|
589 |
|
590 // |
|
591 // Set up the descriptor, length=0, maxlen=readLen+destOffset |
|
592 // |
|
593 iBuffer->GetDes( des, 0, readLen + destOffset ); |
|
594 |
|
595 #if 0 |
|
596 test( KErrNone == iDrive.Read( 0, readLen, &des, iDummyThread.Handle(), destOffset ) ); |
|
597 #else |
|
598 test( KErrNone == iDrive.Read( 0, readLen, &des, KLocalMessageHandle, destOffset ) ); |
|
599 #endif |
|
600 |
|
601 // |
|
602 // Check what we got |
|
603 // |
|
604 test( des.Length() == readLen + destOffset ); |
|
605 |
|
606 TPtrC8 newDes; |
|
607 iBuffer->GetDes( newDes ); |
|
608 test( newDes.Ptr() == des.Ptr() ); |
|
609 |
|
610 // |
|
611 // end of written data is at readLen + destOffset |
|
612 // |
|
613 test( iBuffer->CheckGuard( readLen+destOffset ) ); |
|
614 // |
|
615 // check the section between that start of the user data and |
|
616 // the offset position still contains guard data |
|
617 // |
|
618 test( iBuffer->CheckGuardAtStartOfUserData( destOffset ) ); |
|
619 |
|
620 test( CompareAgainstFlash( 0, des, destOffset ) ); |
|
621 } |
|
622 |
|
623 } |
|
624 } |
|
625 |
|
626 |
|
627 void CReadTest::TestOffsetBufferUnalignedThreadReads() |
|
628 // |
|
629 // Makes reads of 1 byte to 512 bytes to an offset position in the |
|
630 // checked buffer and tests that only the expected bytes have changed |
|
631 // This uses the more complex read function from TBusLocalDrive, and |
|
632 // reads from an aligned Flash address |
|
633 // |
|
634 { |
|
635 test.Next( _L("Testing other-thread unaligned reads into offset position in descriptor\n") ); |
|
636 |
|
637 // |
|
638 // Descriptor to user data area, passed to media driver |
|
639 // |
|
640 TPtr8 des(0,0); |
|
641 |
|
642 for( TInt readLen = 1; readLen <= 500; readLen++ ) |
|
643 { |
|
644 test.Printf( _L("Reading %d bytes\n"), readLen ); |
|
645 |
|
646 |
|
647 // |
|
648 // Repeat test for offsets 0..64 in buffer |
|
649 // |
|
650 for( TInt destOffset = 1; destOffset < 64; destOffset++ ) |
|
651 { |
|
652 // test.Printf( _L("... dest offset = %d"), destOffset ); |
|
653 |
|
654 // |
|
655 // repeat for each source offset |
|
656 // |
|
657 for( TInt offs = 1; offs < 4; offs++ ) |
|
658 { |
|
659 // |
|
660 // Prepare the guard data |
|
661 // |
|
662 iBuffer->InitialiseGuard(); |
|
663 |
|
664 // |
|
665 // Set up the descriptor, length=0, maxlen=readLen+destOffset |
|
666 // |
|
667 iBuffer->GetDes( des, 0, readLen + destOffset ); |
|
668 |
|
669 #if 0 |
|
670 test( KErrNone == iDrive.Read( offs, readLen, &des, iDummyThread.Handle(), destOffset ) ); |
|
671 #else |
|
672 test( KErrNone == iDrive.Read( offs, readLen, &des, KLocalMessageHandle, destOffset ) ); |
|
673 #endif |
|
674 |
|
675 |
|
676 // |
|
677 // Check what we got |
|
678 // |
|
679 test( des.Length() == readLen + destOffset ); |
|
680 |
|
681 TPtrC8 newDes; |
|
682 iBuffer->GetDes( newDes ); |
|
683 test( newDes.Ptr() == des.Ptr() ); |
|
684 |
|
685 // |
|
686 // end of written data is at readLen + destOffset |
|
687 // |
|
688 test( iBuffer->CheckGuard( readLen+destOffset ) ); |
|
689 // |
|
690 // check the section between that start of the user data and |
|
691 // the offset position still contains guard data |
|
692 // |
|
693 test( iBuffer->CheckGuardAtStartOfUserData( destOffset ) ); |
|
694 |
|
695 test( CompareAgainstFlash( offs, des, destOffset ) ); |
|
696 } // end for |
|
697 } |
|
698 } |
|
699 } |
|
700 |
|
701 |
|
702 void CReadTest::PerformCheckedRead( TInt aReadPos, TInt aReadLen ) |
|
703 { |
|
704 TPtr8 des(0,0); |
|
705 iBuffer->InitialiseGuard(); |
|
706 iBuffer->GetDes( des, 0, aReadLen ); |
|
707 |
|
708 test.Printf( _L("Reading %d byte(s) from offset 0x%x\n"), aReadLen, aReadPos ); |
|
709 test( KErrNone == iDrive.Read( aReadPos, aReadLen, des ) ); |
|
710 test( des.Length() == aReadLen ); |
|
711 test( iBuffer->CheckGuard( aReadLen ) ); |
|
712 test( CompareAgainstFlash( aReadPos, des, 0 ) ); |
|
713 } |
|
714 |
|
715 void CReadTest::PerformCheckedThreadRead( TInt aReadPos, TInt aReadLen, TInt aDescOffset ) |
|
716 { |
|
717 TPtr8 des(0,0); |
|
718 iBuffer->InitialiseGuard(); |
|
719 iBuffer->GetDes( des, 0, aReadLen + aDescOffset ); |
|
720 |
|
721 test.Printf( _L("Reading %d byte(s) from offset 0x%x to thread descriptor offset %d\n"), aReadLen, aReadPos, aDescOffset ); |
|
722 #if 0 |
|
723 test( KErrNone == iDrive.Read( aReadPos, aReadLen, &des, iDummyThread.Handle(), aDescOffset ) ); |
|
724 #else |
|
725 test( KErrNone == iDrive.Read( aReadPos, aReadLen, &des, KLocalMessageHandle, aDescOffset ) ); |
|
726 #endif |
|
727 |
|
728 // test.Printf( _L("Check descriptor length") ); |
|
729 test( des.Length() == aReadLen + aDescOffset ); |
|
730 // test.Printf( _L("Check guard") ); |
|
731 test( iBuffer->CheckGuard( aReadLen + aDescOffset ) ); |
|
732 // test.Printf( _L("Check guard at start of descriptor") ); |
|
733 test( iBuffer->CheckGuardAtStartOfUserData( aDescOffset ) ); |
|
734 test( CompareAgainstFlash( aReadPos, des, aDescOffset ) ); |
|
735 } |
|
736 |
|
737 |
|
738 void CReadTest::TestReadsFromAllBlocks() |
|
739 // |
|
740 // Does some spot-test reads from all blocks to make sure |
|
741 // that reading across the whole Flash works |
|
742 // |
|
743 { |
|
744 test.Next( _L("Testing reads from all blocks\n") ); |
|
745 |
|
746 for( TInt block = 0; block < iBlockCount; block++ ) |
|
747 { |
|
748 test.Printf( _L("Reading from block %d"), block ); |
|
749 TInt readBase = (block * iBlockSize); |
|
750 |
|
751 PerformCheckedRead( readBase, 1 ); |
|
752 PerformCheckedRead( readBase, 24 ); |
|
753 PerformCheckedRead( readBase, 99 ); |
|
754 PerformCheckedRead( readBase, 511 ); |
|
755 PerformCheckedRead( readBase+1, 1 ); |
|
756 PerformCheckedRead( readBase+1, 24 ); |
|
757 PerformCheckedRead( readBase+1, 99 ); |
|
758 PerformCheckedRead( readBase+1, 511 ); |
|
759 PerformCheckedRead( readBase+3, 1 ); |
|
760 PerformCheckedRead( readBase+3, 24 ); |
|
761 PerformCheckedRead( readBase+3, 99 ); |
|
762 PerformCheckedRead( readBase+3, 511 ); |
|
763 |
|
764 PerformCheckedThreadRead( readBase, 1, 0 ); |
|
765 PerformCheckedThreadRead( readBase, 24, 0 ); |
|
766 PerformCheckedThreadRead( readBase, 99, 2 ); |
|
767 PerformCheckedThreadRead( readBase, 511, 0 ); |
|
768 PerformCheckedThreadRead( readBase+1, 1, 11 ); |
|
769 PerformCheckedThreadRead( readBase+1, 24, 4 ); |
|
770 PerformCheckedThreadRead( readBase+1, 99, 24 ); |
|
771 PerformCheckedThreadRead( readBase+1, 511, 0 ); |
|
772 PerformCheckedThreadRead( readBase+3, 1, 32 ); |
|
773 PerformCheckedThreadRead( readBase+3, 24, 333 ); |
|
774 PerformCheckedThreadRead( readBase+3, 99, 0 ); |
|
775 PerformCheckedThreadRead( readBase+3, 511, 1 ); |
|
776 } |
|
777 } |
|
778 |
|
779 void CReadTest::TestSimpleScatterReads1() |
|
780 // |
|
781 // Does some simple reads of varying length from the |
|
782 // blocks in pseudo-random order. |
|
783 // |
|
784 { |
|
785 test.Next( _L("Testing simple scatter reads\n") ); |
|
786 |
|
787 TRandomGenerator random; |
|
788 random.SetSeed( KRandomTestSeed ); |
|
789 |
|
790 for( TInt readLen = 1; readLen <= 512; readLen++ ) |
|
791 { |
|
792 TInt block = random.Next() % iBlockCount; |
|
793 test.Printf( _L("Reading block %d"), block ); |
|
794 TInt readBase = (block * iBlockSize); |
|
795 PerformCheckedRead( readBase, readLen ); |
|
796 } |
|
797 } |
|
798 |
|
799 void CReadTest::TestSimpleScatterReads2() |
|
800 // |
|
801 // Does some simple reads of varying length from the |
|
802 // blocks in pseudo-random order. |
|
803 // |
|
804 // This is similar to TestSimpleScatterReads1 except that |
|
805 // as the length reduces the read position is moved along |
|
806 // and the test uses the thread-read variant |
|
807 // |
|
808 { |
|
809 test.Next( _L("Testing simple scatter reads\n") ); |
|
810 |
|
811 TRandomGenerator random; |
|
812 random.SetSeed( KRandomTestSeed ); |
|
813 |
|
814 for( TInt readLen = 1; readLen <= 512; readLen++ ) |
|
815 { |
|
816 TInt block = random.Next() % iBlockCount; |
|
817 test.Printf( _L("Reading block %d"), block ); |
|
818 TInt readBase = (block * iBlockSize) + (512 - readLen); |
|
819 PerformCheckedRead( readBase, readLen ); |
|
820 } |
|
821 } |
|
822 |
|
823 void CReadTest::TestScatterGather() |
|
824 // |
|
825 // This reads bytes from all over the Flash and concatenates |
|
826 // them into a single descriptor. This isn't representative of |
|
827 // anything a real filesystem would do (at present!) but |
|
828 // is an interesting test of the media driver |
|
829 // |
|
830 { |
|
831 test.Next( _L("Testing scatter-gather reads\n") ); |
|
832 |
|
833 TRandomGenerator random; |
|
834 random.SetSeed( KRandomTestSeed ); |
|
835 |
|
836 const TInt KMaxReads = 500; |
|
837 struct SReadInfo |
|
838 { |
|
839 TInt iOffset; |
|
840 TInt iLength; |
|
841 }; |
|
842 |
|
843 SReadInfo* readInfoArray = new SReadInfo[KMaxReads]; |
|
844 test( NULL != readInfoArray ); |
|
845 |
|
846 TPtr8 des(0,0); |
|
847 iBuffer->InitialiseGuard(); |
|
848 iBuffer->GetDes( des, 0, KTestUserDataSize ); |
|
849 TInt descOffset = 0; |
|
850 |
|
851 TInt readCount; |
|
852 for( readCount = 0; readCount < KMaxReads; readCount++ ) |
|
853 { |
|
854 // |
|
855 // Create random read position and length |
|
856 // |
|
857 TInt block = random.Next() % iBlockCount; |
|
858 TInt blockOffset = random.Next() % 1000; |
|
859 if( blockOffset > 500 ) |
|
860 { |
|
861 blockOffset = iBlockSize - 1 - blockOffset; |
|
862 } |
|
863 TInt readOffset = (block * iBlockSize) + blockOffset; |
|
864 TInt readLength = (random.Next() % 8) + 1; |
|
865 |
|
866 if( des.Length() + readLength > des.MaxLength() ) |
|
867 { |
|
868 break; // finished |
|
869 } |
|
870 |
|
871 // |
|
872 // Save the position & length |
|
873 // |
|
874 readInfoArray[readCount].iOffset = readOffset; |
|
875 readInfoArray[readCount].iLength = readLength; |
|
876 |
|
877 // |
|
878 // do the read |
|
879 // |
|
880 _LIT( KScatterReadMsg, "Reading Flash @%x %d bytes to desc offset %d" ); |
|
881 test.Printf( KScatterReadMsg, readOffset, readLength, descOffset ); |
|
882 #if 0 |
|
883 test( KErrNone == iDrive.Read( readOffset, readLength, &des, iDummyThread.Handle(), descOffset ) ); |
|
884 #else |
|
885 test( KErrNone == iDrive.Read( readOffset, readLength, &des, KLocalMessageHandle, descOffset ) ); |
|
886 #endif |
|
887 test( des.Length() == descOffset + readLength ); |
|
888 |
|
889 descOffset += readLength; |
|
890 } |
|
891 |
|
892 // |
|
893 // Now check all the data against the Flash contents |
|
894 // |
|
895 descOffset = 0; |
|
896 for( TInt i = 0; i < readCount; i++ ) |
|
897 { |
|
898 TInt readOffset = readInfoArray[i].iOffset ; |
|
899 TInt readLength = readInfoArray[i].iLength; |
|
900 |
|
901 TPtrC8 ptr( des.Ptr() + descOffset, readLength ); |
|
902 test( CompareAgainstFlash( readOffset, ptr, 0 ) ); |
|
903 descOffset += readLength; |
|
904 } |
|
905 |
|
906 delete[] readInfoArray; |
|
907 |
|
908 } |
|
909 |
|
910 |
|
911 |
|
912 void CReadTest::TestReadAcrossBlock() |
|
913 // |
|
914 // Test reads that cross a block boundary |
|
915 // |
|
916 { |
|
917 test.Next( _L("Testing reads across block boundary\n") ); |
|
918 |
|
919 for( TInt block = 1; block < iBlockCount - 1; block++ ) |
|
920 { |
|
921 for( TInt readLen = 2; readLen <= 1024; readLen++ ) |
|
922 { |
|
923 TInt blockBase = (block * iBlockSize); |
|
924 TInt readOffs = blockBase + (iBlockSize - (readLen/2)); |
|
925 PerformCheckedRead( readOffs, readLen ); |
|
926 } |
|
927 } |
|
928 } |
|
929 |
|
930 |
|
931 |
|
932 void CReadTest::CreateSampleData() |
|
933 // |
|
934 // Fills iSampleData with pseudo-random test data |
|
935 // |
|
936 { |
|
937 TUint32* p = (TUint32*)iSampleData.Ptr(); |
|
938 for( TInt j = 0; j < KTestUserDataSize/4; j++ ) |
|
939 { |
|
940 *p++ = iRandom.Next(); |
|
941 } |
|
942 |
|
943 iSampleData.SetLength( KTestUserDataSize ); |
|
944 } |
|
945 |
|
946 |
|
947 TBool CReadTest::CheckZero( const TPtrC8& aDes ) |
|
948 // |
|
949 // Checks that all bytes in aDes are zero |
|
950 // |
|
951 { |
|
952 for( TInt i = aDes.Length(); i > 0; ) |
|
953 { |
|
954 --i; |
|
955 if( 0 != aDes[i] ) |
|
956 { |
|
957 return EFalse; |
|
958 } |
|
959 } |
|
960 return ETrue; |
|
961 } |
|
962 |
|
963 |
|
964 |
|
965 void CReadTest::CreateTestData( TInt aBlockNumber, TBool aEndOfBlock ) |
|
966 // |
|
967 // Writes some test data to the Flash. If aEndOfBlock is EFalse the |
|
968 // data is created at the start of the block. If it is ETrue then |
|
969 // the data is created right at the end of the block |
|
970 // |
|
971 { |
|
972 |
|
973 test.Printf( _L("Writing test data to Flash block %d\n"), aBlockNumber ); |
|
974 |
|
975 // |
|
976 // Generate some test data |
|
977 // |
|
978 CreateSampleData(); |
|
979 |
|
980 test.Printf( _L("Erasing block") ); |
|
981 TInt writeBaseOffset = (aBlockNumber * iBlockSize); |
|
982 test( KErrNone == iDrive.Format( writeBaseOffset, iBlockSize ) ); |
|
983 |
|
984 |
|
985 TInt writeCount = iSampleData.Length() / KMaxWriteLength; |
|
986 TInt r = KErrNone; |
|
987 if( aEndOfBlock ) |
|
988 { |
|
989 writeBaseOffset += iBlockSize - iSampleData.Length(); |
|
990 } |
|
991 |
|
992 TInt writeOffset = writeBaseOffset; |
|
993 |
|
994 const TUint8* src = iSampleData.Ptr(); |
|
995 |
|
996 test.Printf( _L("Writing data") ); |
|
997 for( ; (writeCount > 0) && (KErrNone == r); writeCount-- ) |
|
998 { |
|
999 TPtrC8 buf( src, KMaxWriteLength ); |
|
1000 test( KErrNone == iDrive.Write( writeOffset, buf ) ); |
|
1001 writeOffset += KMaxWriteLength; |
|
1002 src += KMaxWriteLength; |
|
1003 } |
|
1004 test( r == KErrNone ); |
|
1005 |
|
1006 // |
|
1007 // check that the data was written ok |
|
1008 // |
|
1009 test.Printf( _L("Verifying data") ); |
|
1010 test( CompareAgainstFlash( writeBaseOffset, iSampleData, 0 ) ); |
|
1011 |
|
1012 test.Printf( _L("... test data written\n") ); |
|
1013 } |
|
1014 |
|
1015 TBool CReadTest::CompareAgainstFlash( TInt aFlashOffset, const TPtrC8& aDes, TInt aDescOffset ) |
|
1016 // |
|
1017 // Checks that the data in aDes matches that in the Flash at position |
|
1018 // aFlashOffset. |
|
1019 // The test starts at offset aDescOffset in aSampleData. The data length |
|
1020 // tested is aDes->Length() - aDescOffset |
|
1021 // |
|
1022 { |
|
1023 TInt dataLength = aDes.Length() - aDescOffset; |
|
1024 const TUint8* srcPtr = aDes.Ptr() + aDescOffset; |
|
1025 |
|
1026 TUint offset = aFlashOffset; |
|
1027 |
|
1028 TBool failed = EFalse; |
|
1029 const TInt readBufLen = iReadBuffer.MaxLength(); |
|
1030 |
|
1031 while( (dataLength > 0) && !failed ) |
|
1032 { |
|
1033 TInt len = Min( dataLength, readBufLen ); |
|
1034 TInt r = iDrive.Read( offset, len, iReadBuffer ); |
|
1035 if( r != KErrNone ) |
|
1036 { |
|
1037 test.Printf( _L("... FAIL: read failed (%d) at offset 0x%x\n"), r, offset ); |
|
1038 test( KErrNone == r ); |
|
1039 } |
|
1040 test( iReadBuffer.Length() == len ); |
|
1041 |
|
1042 if( 0 != Mem::Compare( srcPtr, len, iReadBuffer.Ptr(), len ) ) |
|
1043 { |
|
1044 test.Printf( _L("... FAIL: mismatch around offset 0x%x\n"), offset ); |
|
1045 failed = ETrue; |
|
1046 } |
|
1047 offset += len; |
|
1048 dataLength -= len; |
|
1049 srcPtr += len; |
|
1050 } |
|
1051 |
|
1052 return !failed; |
|
1053 } |
|
1054 |
|
1055 |
|
1056 |
|
1057 void CReadTest::DoTest() |
|
1058 // |
|
1059 // Main test dispatcher |
|
1060 // |
|
1061 { |
|
1062 // |
|
1063 // Create some test data at start of block 0 |
|
1064 // |
|
1065 CreateTestData( 0, EFalse ); |
|
1066 |
|
1067 // |
|
1068 // Now do the simple tests, all reads will return zeros |
|
1069 // |
|
1070 #if 0 |
|
1071 TestSimpleReads(); |
|
1072 #endif |
|
1073 TestSimpleThreadReads(); |
|
1074 TestUnalignedReads(); |
|
1075 TestUnalignedThreadReads(); |
|
1076 TestOffsetBufferThreadReads(); |
|
1077 TestOffsetBufferUnalignedThreadReads(); |
|
1078 |
|
1079 // |
|
1080 // Create some more data at start of all other blocks |
|
1081 // |
|
1082 test.Next( _L("Creating more test data in other blocks") ); |
|
1083 for( TInt i = 1; i < iBlockCount; i++ ) |
|
1084 { |
|
1085 CreateTestData( i, EFalse ); |
|
1086 } |
|
1087 |
|
1088 // |
|
1089 // Make sure we can read valid data out of the other blocks |
|
1090 // |
|
1091 TestReadsFromAllBlocks(); |
|
1092 |
|
1093 // |
|
1094 // Now do some scatter-read tests |
|
1095 // |
|
1096 TestSimpleScatterReads1(); |
|
1097 TestSimpleScatterReads2(); |
|
1098 |
|
1099 // |
|
1100 // Create some more testdata at end of all blocks |
|
1101 // |
|
1102 test.Next( _L("Creating test data at end of blocks") ); |
|
1103 for( TInt i = 0; i < iBlockCount; i++ ) |
|
1104 { |
|
1105 CreateTestData( i, ETrue ); |
|
1106 } |
|
1107 |
|
1108 // |
|
1109 // Do a full scatter-gather test |
|
1110 // |
|
1111 TestScatterGather(); |
|
1112 |
|
1113 TestReadAcrossBlock(); |
|
1114 } |
|
1115 |
|
1116 |
|
1117 |
|
1118 |
|
1119 |
|
1120 TInt E32Main() |
|
1121 { |
|
1122 test.Title(); |
|
1123 test.Start(_L("Testing media read operations")); |
|
1124 |
|
1125 CReadTest reader; |
|
1126 TRAPD( ret, reader.CreateL() ); |
|
1127 test( KErrNone == ret ); |
|
1128 reader.DoTest(); |
|
1129 test.End(); |
|
1130 |
|
1131 return 0; |
|
1132 } |