|
1 // Copyright (c) 2007-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 // @file endpointwriter.cpp |
|
15 // @internalComponent |
|
16 // |
|
17 // |
|
18 |
|
19 #include <e32base.h> |
|
20 #include <e32base_private.h> |
|
21 #include <d32usbc.h> |
|
22 #include "endpointwriter.h" |
|
23 #include "testdebug.h" |
|
24 |
|
25 namespace NUnitTesting_USBDI |
|
26 { |
|
27 const TUint KMaxTransferBuffer = 0x1000; |
|
28 |
|
29 |
|
30 CEndpointWriter::CEndpointWriter(RDevUsbcClient& aClientDriver,TEndpointNumber aEndpoint) |
|
31 : CActive(EPriorityStandard), |
|
32 iClientDriver(aClientDriver), |
|
33 iEndpoint(aEndpoint), |
|
34 iBufPtr(NULL,0) |
|
35 { |
|
36 CActiveScheduler::Add(this); |
|
37 } |
|
38 |
|
39 |
|
40 CEndpointWriter::~CEndpointWriter() |
|
41 { |
|
42 LOG_FUNC |
|
43 |
|
44 Cancel(); |
|
45 if(iBuffer) |
|
46 { |
|
47 RDebug::Printf("Freeing %d bytes", iBuffer->Size()); |
|
48 } |
|
49 delete iBuffer; |
|
50 } |
|
51 |
|
52 |
|
53 void CEndpointWriter::DoCancel() |
|
54 { |
|
55 LOG_FUNC |
|
56 |
|
57 // Cancel the write to the endpoint |
|
58 |
|
59 iClientDriver.WriteCancel(iEndpoint); |
|
60 } |
|
61 |
|
62 |
|
63 TUint CEndpointWriter::NumBytesWrittenSoFar() |
|
64 { |
|
65 return iNumBytesWritten; |
|
66 } |
|
67 |
|
68 void CEndpointWriter::RunL() |
|
69 { |
|
70 LOG_FUNC |
|
71 |
|
72 TInt completionCode(iStatus.Int()); |
|
73 RDebug::Printf("Write completed, err=%d",completionCode); |
|
74 |
|
75 iNumBytesWritten += iNumBytesOnCurrentWrite; // all zero if not a repeated write |
|
76 if(iNumBytesWritten < iTotalNumBytes) |
|
77 //This conditional will not be entered for non-repeat cases because then |
|
78 //'iNumBytesWritten' and 'iTotalNumBytes' will both be zero. |
|
79 { |
|
80 TUint totalNumBytesStillToWrite = iTotalNumBytes - iNumBytesWritten; |
|
81 |
|
82 //NB iNumBytesOnCurrentWrite should remain at the requested 'bytes per Write' value until the last iteration |
|
83 iNumBytesOnCurrentWrite = totalNumBytesStillToWrite <= iNumBytesOnCurrentWrite ? totalNumBytesStillToWrite : iNumBytesOnCurrentWrite; |
|
84 |
|
85 //Only add a ZLP, if requested and if the last 'Write' |
|
86 TBool useUsb = totalNumBytesStillToWrite <= iNumBytesOnCurrentWrite ? iUseZLP : EFalse; |
|
87 TPtrC8 writeDesc = iBufPtr.Mid(iNumBytesWritten%iDataPatternLength, iNumBytesOnCurrentWrite); |
|
88 RDebug::Printf("Total Bytes To Write = %d, Bytes Still To Write = %d, Bytes Written = %d, Bytes on Current 'Write'", iTotalNumBytes, totalNumBytesStillToWrite, iNumBytesWritten, iNumBytesOnCurrentWrite); |
|
89 |
|
90 RDebug::Printf("\n"); |
|
91 RDebug::Printf("First 256 bytes (or all) of data to write"); |
|
92 RDebug::RawPrint(writeDesc); |
|
93 RDebug::Printf("\n"); |
|
94 |
|
95 |
|
96 Write(writeDesc, useUsb, EFalse); |
|
97 } |
|
98 else |
|
99 { |
|
100 if(iBuffer!=NULL) |
|
101 { |
|
102 RDebug::Printf("Freeing %d bytes", iBuffer->Size()); |
|
103 } |
|
104 else |
|
105 { |
|
106 RDebug::Printf("iBuffer is NULL"); |
|
107 } |
|
108 if(iTotalNumBytes != 0) |
|
109 //if a repeated write |
|
110 { |
|
111 RDebug::Printf("Total Bytes = %d, Bytes Written = %d", iTotalNumBytes, iNumBytesWritten); |
|
112 } |
|
113 delete iBuffer; |
|
114 iBuffer = 0; |
|
115 iNumBytesOnCurrentWrite = 0; |
|
116 iNumBytesWritten = 0; |
|
117 iTotalNumBytes = 0; |
|
118 iDataPatternLength = 0; |
|
119 iUseZLP = EFalse; |
|
120 } |
|
121 } |
|
122 |
|
123 |
|
124 TInt CEndpointWriter::RunError(TInt aError) |
|
125 { |
|
126 LOG_FUNC |
|
127 |
|
128 aError = KErrNone; |
|
129 return aError; |
|
130 } |
|
131 |
|
132 |
|
133 void CEndpointWriter::Write(const TDesC8& aData, TBool aUseZLP, TBool aCreateBuffer) |
|
134 { |
|
135 LOG_FUNC |
|
136 |
|
137 if(aCreateBuffer == EFalse) |
|
138 { |
|
139 RDebug::Printf("Use ZLP %d", aUseZLP?1:0); |
|
140 iClientDriver.Write(iStatus,iEndpoint,aData,aData.Length(),aUseZLP); |
|
141 SetActive(); |
|
142 return; |
|
143 } |
|
144 |
|
145 |
|
146 //Copy aData to this object's buffer |
|
147 //'aData' will go out of scope before the USB driver 'Write' completes |
|
148 delete iBuffer; |
|
149 iBuffer = NULL; |
|
150 iBuffer = HBufC8::NewL(aData.Length()); |
|
151 iBufPtr.Set(iBuffer->Des()); |
|
152 iBufPtr.Copy(aData); |
|
153 |
|
154 // Write the data to the host through the endpoint (host opened pipe) |
|
155 RDebug::Printf("Write Length = %d", iBufPtr.Length()); |
|
156 RDebug::RawPrint(iBufPtr); |
|
157 RDebug::Printf("\n"); |
|
158 RDebug::Printf("Use ZLP %d", aUseZLP?1:0); |
|
159 iClientDriver.Write(iStatus,iEndpoint,iBufPtr,iBufPtr.Length(),aUseZLP); |
|
160 SetActive(); |
|
161 } |
|
162 |
|
163 TInt CEndpointWriter::WriteSynchronous(const TDesC8& aData, TBool aUseZLP) |
|
164 { |
|
165 LOG_FUNC |
|
166 |
|
167 TRequestStatus status = KRequestPending; |
|
168 RDebug::Printf("Write Length = %d", aData.Length()); |
|
169 RDebug::RawPrint(aData); |
|
170 RDebug::Printf("\n"); |
|
171 RDebug::Printf("Use ZLP %d", aUseZLP?1:0); |
|
172 iClientDriver.Write(status,iEndpoint,aData,aData.Length(),aUseZLP); |
|
173 User::WaitForRequest(status); |
|
174 RDebug::Printf("Write has completed with error %d", status.Int()); |
|
175 return status.Int(); |
|
176 } |
|
177 |
|
178 void CEndpointWriter::WriteSynchronousUsingPatternL(const TDesC8& aData, const TUint aNumBytes, const TBool aUseZLP) |
|
179 { |
|
180 LOG_FUNC |
|
181 |
|
182 TBool useZLP = EFalse; //only want this if you are making the last call to client Write (=WriteSynchronous) |
|
183 if(aNumBytes <= aData.Length()) |
|
184 //Don't need to allocate a buffer and copy to it - write will be done synchronously |
|
185 { |
|
186 if(aUseZLP) |
|
187 { |
|
188 useZLP = ETrue; |
|
189 } |
|
190 WriteSynchronous(aData.Left(aNumBytes),useZLP); |
|
191 } |
|
192 |
|
193 else if(aNumBytes <= KMaxTransferBuffer) |
|
194 //Create a buffer based on the data pattern sent and use just one 'Synchronous Write' |
|
195 { |
|
196 if(aUseZLP) |
|
197 { |
|
198 useZLP = ETrue; |
|
199 } |
|
200 TInt repeats = aNumBytes/aData.Length(); |
|
201 TInt extraBytes = aNumBytes%aData.Length(); |
|
202 delete iBuffer; |
|
203 iBuffer = NULL; |
|
204 iBuffer = HBufC8::NewL(aNumBytes); |
|
205 TPtr8 ptr = iBuffer->Des(); |
|
206 ptr.Zero(); |
|
207 for(TUint i =0; i<repeats; i++) |
|
208 { |
|
209 ptr.Append(aData); |
|
210 } |
|
211 if(extraBytes) |
|
212 { |
|
213 ptr.Append(aData.Left(extraBytes)); |
|
214 } |
|
215 WriteSynchronous(ptr, useZLP); |
|
216 delete iBuffer; |
|
217 } |
|
218 |
|
219 else |
|
220 //Create a buffer based on the data pattern sent and use SEVERAL 'Synchronous Write's |
|
221 { |
|
222 //Write data in reasonably sized chunks |
|
223 //Create buffer using max whole number of data patterns |
|
224 TInt repeats = KMaxTransferBuffer/aData.Length(); |
|
225 CreateBigBuffer(aData, repeats); |
|
226 |
|
227 //Now write data |
|
228 repeats = aNumBytes/iBufPtr.Length(); //re-use 'repeats' |
|
229 TInt endBytes = aNumBytes%iBufPtr.Length(); |
|
230 for(TInt i=0;i<repeats;i++) |
|
231 { |
|
232 if(i==(repeats-1)&&endBytes==0) |
|
233 //last loop - request ZLP if appropriate |
|
234 { |
|
235 WriteSynchronous(*iBuffer, aUseZLP); //if last 'Write' |
|
236 } |
|
237 else |
|
238 { |
|
239 WriteSynchronous(*iBuffer, EFalse); |
|
240 } |
|
241 } |
|
242 if(endBytes) |
|
243 { |
|
244 WriteSynchronous(iBufPtr.Left(endBytes), aUseZLP); //if last 'Write' |
|
245 } |
|
246 } |
|
247 delete iBuffer; |
|
248 iBuffer = 0; |
|
249 } |
|
250 |
|
251 void CEndpointWriter::WriteSynchronousUsingPatternL(const TDesC8& aData, const TUint aNumBytes) |
|
252 { |
|
253 WriteSynchronousUsingPatternL(aData, aNumBytes, ETrue); |
|
254 } |
|
255 |
|
256 void CEndpointWriter::WriteSynchronousUsingPatternAndHaltL(const TDesC8& aData, const TUint aNumBytes) |
|
257 { |
|
258 LOG_FUNC |
|
259 WriteSynchronousUsingPatternL(aData, aNumBytes, EFalse); |
|
260 iClientDriver.HaltEndpoint(iEndpoint); |
|
261 } |
|
262 |
|
263 void CEndpointWriter::WriteUsingPatternL(const TDesC8& aData, const TUint aNumBytes, const TBool aUseZLP) |
|
264 { |
|
265 LOG_FUNC |
|
266 |
|
267 RDebug::Printf("Allocating %d bytes", aNumBytes); |
|
268 delete iBuffer; |
|
269 iBuffer = NULL; |
|
270 iBuffer = HBufC8::NewL(aNumBytes); |
|
271 RDebug::Printf("Allocated %d bytes", aNumBytes); |
|
272 iBufPtr.Set(iBuffer->Des()); |
|
273 iBufPtr.Zero(); |
|
274 TInt repeats = aNumBytes/aData.Length(); |
|
275 for(TUint i =0; i<repeats; i++) |
|
276 { |
|
277 iBufPtr.Append(aData); |
|
278 } |
|
279 if(TInt extraBytes = aNumBytes%aData.Length()) |
|
280 { |
|
281 iBufPtr.Append(aData.Left(extraBytes)); |
|
282 } |
|
283 Write(*iBuffer, aUseZLP, EFalse); |
|
284 } |
|
285 |
|
286 void CEndpointWriter::WriteInPartsUsingPatternL(const TDesC8& aData, const TUint aNumBytesPerWrite, TUint aTotalNumBytes, const TBool aUseZLP) |
|
287 { |
|
288 LOG_FUNC |
|
289 |
|
290 iUseZLP = aUseZLP; |
|
291 TInt repeats = aNumBytesPerWrite/aData.Length() + 1; |
|
292 repeats *= 2; |
|
293 CreateBigBuffer(aData, repeats); |
|
294 iDataPatternLength = aData.Length(); |
|
295 iTotalNumBytes = aTotalNumBytes; |
|
296 iNumBytesOnCurrentWrite = aNumBytesPerWrite; |
|
297 iNumBytesWritten = 0; |
|
298 Write(iBufPtr.Mid(iNumBytesWritten%iDataPatternLength, iNumBytesOnCurrentWrite), EFalse, EFalse); //this is not the first 'Write' so do not use a ZLP |
|
299 RDebug::Printf("Write %d bytes",iNumBytesOnCurrentWrite); |
|
300 RDebug::Printf("Total Bytes = %d, Data Pattern Length = %d", iTotalNumBytes, iDataPatternLength); |
|
301 } |
|
302 |
|
303 void CEndpointWriter::CreateBigBuffer(const TDesC8& aData, const TUint aRepeats) |
|
304 /* |
|
305 Create a payload buffer a section of which can always be used for each cyclic 'Write'. |
|
306 */ |
|
307 { |
|
308 //We require a buffer containing a sufficient number of repeats of the data pattern |
|
309 //to allow us simply to use a section of it for any individual 'Write' payload. |
|
310 delete iBuffer; |
|
311 iBuffer = NULL; |
|
312 RDebug::Printf("Data buffer is using %d repeats of string starting...\n\"%S\"", aRepeats, &aData); |
|
313 iBuffer = HBufC8::NewL(aRepeats*aData.Length()); |
|
314 iBufPtr.Set(iBuffer->Des()); |
|
315 iBufPtr.Zero(); |
|
316 for(TUint i =0; i<aRepeats; i++) |
|
317 { |
|
318 iBufPtr.Append(aData); |
|
319 } |
|
320 } |
|
321 |
|
322 } |