|
1 // Copyright (c) 1996-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 |
|
17 #include "d_comm.h" |
|
18 |
|
19 CCommTxBuf::CCommTxBuf() |
|
20 : CCirBuffer() |
|
21 {} |
|
22 |
|
23 |
|
24 TInt CCommTxBuf::ClientRead(DComm* aDriver, DThread* aThread, const TAny* aPtr, TInt& aTxLength, TInt& aTxOffset, TInt aMode) |
|
25 // |
|
26 // Copy from client to buffer. |
|
27 // |
|
28 { |
|
29 TInt offset = aTxOffset; |
|
30 TInt length = aTxLength; |
|
31 if (length==0) |
|
32 return KErrNone; |
|
33 |
|
34 TPtr8 des(NULL,0); |
|
35 |
|
36 aDriver->DisableInterrupts(); |
|
37 TInt count = iCount; |
|
38 TInt space = iLength-count; |
|
39 if (space==0) |
|
40 { |
|
41 aDriver->EnableInterrupts(); |
|
42 return KErrOverflow; |
|
43 } |
|
44 TInt maxcopy = Min(space,length); |
|
45 aDriver->EnableInterrupts(); |
|
46 |
|
47 TInt copylen = Min(maxcopy, iPtrE-iHead); |
|
48 des.Set(iHead, copylen, copylen); |
|
49 aThread->Read(aPtr, &des, offset, aMode); |
|
50 length -= copylen; |
|
51 offset += copylen; |
|
52 |
|
53 copylen = maxcopy-copylen; |
|
54 if (copylen>0) |
|
55 { |
|
56 des.Set(iPtr, copylen, copylen); |
|
57 aThread->Read(aPtr, &des, offset, aMode); |
|
58 length -= copylen; |
|
59 offset += copylen; |
|
60 } |
|
61 |
|
62 iHead += maxcopy; |
|
63 if (iHead>=iPtrE) |
|
64 iHead -= iLength; |
|
65 |
|
66 aDriver->DisableInterrupts(); |
|
67 iCount += maxcopy; |
|
68 aDriver->EnableInterrupts(); |
|
69 |
|
70 aTxLength = length; |
|
71 aTxOffset = offset; |
|
72 return KErrNone; |
|
73 } |
|
74 |
|
75 |
|
76 CCommRxBuf::CCommRxBuf() |
|
77 // |
|
78 // |
|
79 // |
|
80 { |
|
81 __DECLARE_NAME(_S("CCommRxBuf")); |
|
82 } |
|
83 |
|
84 CCommRxBuf::~CCommRxBuf() |
|
85 // |
|
86 // |
|
87 // |
|
88 { |
|
89 User::Free(iCharPtr); |
|
90 } |
|
91 |
|
92 void CCommRxBuf::SetLengthL(TInt aLength) |
|
93 // |
|
94 // ReAlloc - Resets all the buffer pointers |
|
95 // |
|
96 { |
|
97 __ASSERT_ALWAYS(aLength>0,User::Panic(_L("DCOMBUF"),0/*ECircSetLengthNegative*/)); |
|
98 aLength = Align4(aLength); |
|
99 iCharPtr=(TUint8 *)User::ReAllocL(iCharPtr, aLength<<1); |
|
100 iLength = aLength; |
|
101 iInfoPtr = iCharPtr+aLength; |
|
102 Reset(); |
|
103 } |
|
104 |
|
105 void CCommRxBuf::Reset() |
|
106 // |
|
107 // Reset the buffer pointers |
|
108 // |
|
109 { |
|
110 iCount = 0; |
|
111 iInsP = 0; |
|
112 iRemP = 0; |
|
113 iInsSeqNum = 0; |
|
114 iRemSeqNum = iInsSeqNum; |
|
115 iLastSeqNum = iInsSeqNum; |
|
116 } |
|
117 |
|
118 |
|
119 TInt CCommRxBuf::ClientWrite(TUint& aStatus, DComm* aDriver, DThread* aThread, const TAny* aPtr, TInt& aRxLength, TInt& aRxOffset, TInt aMode) |
|
120 // |
|
121 // Copy to client's buffer |
|
122 // if aCount==0 then do as much as possible, and only return completed |
|
123 // if the clients buffer is full. Normally, aCount would be the count |
|
124 // returned by GetInfo(). |
|
125 // |
|
126 { |
|
127 if (iCount==0) |
|
128 return KErrUnderflow; |
|
129 |
|
130 TInt blocksz; |
|
131 TUint state = iInfoPtr[iRemP]; |
|
132 |
|
133 TInt p; |
|
134 if ((state & 0x0f)==0x0f) |
|
135 { |
|
136 p = (iRemP+0x4)&~0x3; |
|
137 if (p>=iLength) |
|
138 p = 0; |
|
139 blocksz = *((TInt*)(iInfoPtr+p)); |
|
140 } |
|
141 else |
|
142 blocksz = state & 0x0f; |
|
143 |
|
144 p = iRemP+blocksz; |
|
145 if (blocksz>0) |
|
146 p -= 1; |
|
147 if (p>=iLength) |
|
148 p-=iLength; |
|
149 aStatus = (iInfoPtr[p] << KReceiveIsrShift) & KReceiveIsrMaskComplete; |
|
150 |
|
151 TInt length = aRxLength; |
|
152 TInt offset = aRxOffset; |
|
153 |
|
154 if (blocksz>0 && blocksz<length) |
|
155 length = blocksz; |
|
156 |
|
157 aDriver->DisableInterrupts(); |
|
158 TInt count = iCount; |
|
159 // The number of bytes will will extract in total |
|
160 TInt maxcopy = Min(length, count); |
|
161 // Pre-empt the recv int handler so that the sequence |
|
162 // spaces dont clash |
|
163 iRemSeqNum += maxcopy; |
|
164 if (iRemSeqNum > iLastSeqNum) |
|
165 iLastSeqNum = iRemSeqNum; |
|
166 aDriver->EnableInterrupts(); |
|
167 |
|
168 TInt copylen; |
|
169 TPtrC8 des; |
|
170 copylen = Min(maxcopy, iLength-iRemP); |
|
171 des.Set(iCharPtr+iRemP, copylen); |
|
172 aThread->Write(aPtr, &des, offset, aMode); |
|
173 offset += copylen; |
|
174 length -= copylen; |
|
175 count -= copylen; |
|
176 |
|
177 copylen = Min(length, count); |
|
178 if (copylen>0) |
|
179 { |
|
180 des.Set(iCharPtr, copylen); |
|
181 aThread->Write(aPtr, &des, offset, aMode); |
|
182 length -= copylen; |
|
183 count -= copylen; |
|
184 offset += copylen; |
|
185 } |
|
186 |
|
187 aDriver->DisableInterrupts(); |
|
188 iRemP += maxcopy; |
|
189 |
|
190 if (iRemP >= iLength) |
|
191 iRemP -= iLength; |
|
192 |
|
193 iCount -= maxcopy; |
|
194 |
|
195 aDriver->EnableInterrupts(); |
|
196 |
|
197 if (blocksz>maxcopy) |
|
198 { |
|
199 TInt ptr = iRemP; |
|
200 TInt count = blocksz-maxcopy; |
|
201 if (count<0x0f) |
|
202 iInfoPtr[ptr] = (TUint8)((iInfoPtr[ptr] & 0xf0) | count); |
|
203 else |
|
204 { |
|
205 iInfoPtr[ptr] = (TUint8)((iInfoPtr[ptr] & 0xf0) | 0x0f); |
|
206 // Word align buffer offset and wrap if needed |
|
207 // so a full count can be written |
|
208 ptr = (ptr+0x4)&~0x3; |
|
209 if (ptr>=iLength) |
|
210 ptr = 0; |
|
211 *((TInt*)(iInfoPtr+ptr)) = count; |
|
212 } |
|
213 } |
|
214 |
|
215 aRxOffset = offset; |
|
216 aRxLength = length; |
|
217 |
|
218 if (blocksz>0) |
|
219 return (blocksz-maxcopy)==0 || aRxLength==0; |
|
220 |
|
221 return aRxLength==0; |
|
222 } |
|
223 |
|
224 |
|
225 TInt CCommRxBuf::PutChar(TUint aChar) |
|
226 // |
|
227 // Add char to receive buffer |
|
228 // Return true if this character should complete |
|
229 // a Read(). |
|
230 // |
|
231 { |
|
232 if (iCount>=iLength) |
|
233 return KErrOverflow; |
|
234 |
|
235 iCharPtr[iInsP] = (TUint8)(aChar & 0xff); |
|
236 iInfoPtr[iInsP] = (TUint8)(aChar >> KReceiveIsrShift); |
|
237 if (++iInsP >= iLength) |
|
238 iInsP = 0; |
|
239 ++iCount; |
|
240 ++iInsSeqNum; // Pre-Inc is more efficient for a C++ object |
|
241 |
|
242 // Check if we have to write a new event offset into |
|
243 // the info buffer |
|
244 if (aChar & KReceiveIsrMaskComplete) |
|
245 { |
|
246 TInt count = iInsSeqNum - iLastSeqNum; |
|
247 TInt ptr = iInsP-count; |
|
248 if (ptr<0) |
|
249 ptr += iLength; |
|
250 |
|
251 if (count<0x0f) |
|
252 iInfoPtr[ptr] = (TUint8)((iInfoPtr[ptr] & 0xf0) | count); |
|
253 else |
|
254 { |
|
255 iInfoPtr[ptr] = (TUint8)((iInfoPtr[ptr] & 0xf0) | 0x0f); |
|
256 // Word align buffer offset and wrap if needed |
|
257 // so a full count can be written |
|
258 ptr = (ptr+0x4)&~0x3; |
|
259 if (ptr>=iLength) |
|
260 ptr = 0; |
|
261 *((TInt*)(iInfoPtr+ptr)) = count; |
|
262 } |
|
263 iLastSeqNum = iInsSeqNum; |
|
264 return 1; |
|
265 } |
|
266 |
|
267 return 0; |
|
268 } |
|
269 |
|
270 |
|
271 TBool CCommRxBuf::RescanTerminators(DComm* aDriver, TInt aTermCount, TText8* aTermChars) |
|
272 { |
|
273 aDriver->DisableInterrupts(); |
|
274 |
|
275 TCommSeqNum _rem = iRemSeqNum; |
|
276 |
|
277 // 1. Move last event point to the current insert pointer |
|
278 // This protects from interrupts |
|
279 iLastSeqNum = iInsSeqNum; |
|
280 TCommSeqNum endseq = iLastSeqNum; |
|
281 |
|
282 // 2. Remove all count information, and terminator flags |
|
283 |
|
284 TInt ptr = iRemP; |
|
285 TCommSeqNum seq = iRemSeqNum; |
|
286 |
|
287 while (seq<endseq) |
|
288 { |
|
289 TInt p = ptr; |
|
290 TInt len; |
|
291 TUint s = iInfoPtr[p]; |
|
292 |
|
293 if (s==0) |
|
294 len = endseq-seq; |
|
295 else if ((s & 0x0f)==0x0f) |
|
296 { |
|
297 p = (ptr+0x4)&~0x3; |
|
298 if (p>=iLength) |
|
299 p = 0; |
|
300 len = *((TInt*)(iInfoPtr+p)); |
|
301 *((TInt*)(iInfoPtr+p)) = 0; |
|
302 } |
|
303 else |
|
304 { |
|
305 iInfoPtr[p] &= 0xf0; |
|
306 len = s & 0x0f; |
|
307 } |
|
308 |
|
309 ptr += len; |
|
310 p = ptr; |
|
311 |
|
312 if (len>0) |
|
313 p -= 1; |
|
314 if (p>=iLength) |
|
315 p-=iLength; |
|
316 |
|
317 iInfoPtr[p] &= ~(KReceiveIsrTermChar>>KReceiveIsrShift); |
|
318 |
|
319 if (ptr>=iLength) |
|
320 ptr -= iLength; |
|
321 seq += len; |
|
322 } |
|
323 |
|
324 // 3. Now create a new set of counts and events exactly as if inserting the |
|
325 // characters for the first time. |
|
326 |
|
327 TBool complete = EFalse; |
|
328 TInt lstptr; |
|
329 TCommSeqNum lstseq; |
|
330 |
|
331 ptr = iRemP; |
|
332 seq = iRemSeqNum; |
|
333 |
|
334 lstseq = seq; |
|
335 lstptr = ptr; |
|
336 |
|
337 while (seq<endseq) |
|
338 { |
|
339 ++seq; |
|
340 TText8 c = iCharPtr[ptr]; |
|
341 for (TInt i=0; i<aTermCount; i++) |
|
342 { |
|
343 if (c==aTermChars[i]) |
|
344 { |
|
345 iInfoPtr[ptr] |= (KReceiveIsrTermChar>>KReceiveIsrShift); |
|
346 break; |
|
347 } |
|
348 } |
|
349 |
|
350 if (iInfoPtr[ptr] & (KReceiveIsrMaskComplete>>KReceiveIsrShift)) |
|
351 { |
|
352 TInt len = seq-lstseq; |
|
353 if (len<0x0f) |
|
354 iInfoPtr[lstptr] = (TUint8)((iInfoPtr[lstptr] & 0xf0) | len); |
|
355 else |
|
356 { |
|
357 iInfoPtr[lstptr] = (TUint8)((iInfoPtr[lstptr] & 0xf0) | 0x0f); |
|
358 // Word align buffer offset and wrap if needed |
|
359 // so a full count can be written |
|
360 TInt p = (lstptr+0x4)&~0x3; |
|
361 if (p>=iLength) |
|
362 p = 0; |
|
363 *((TInt*)(iInfoPtr+p)) = len; |
|
364 } |
|
365 lstptr = ptr+1; |
|
366 if (lstptr>=iLength) |
|
367 lstptr -= iLength; |
|
368 lstseq = seq; |
|
369 complete = ETrue; |
|
370 } |
|
371 if (++ptr>=iLength) |
|
372 ptr -= iLength; |
|
373 } |
|
374 |
|
375 // 4. Tie into new location of event seq pointer that may have been moved |
|
376 // as a result of receive interrupts inserting new events |
|
377 if (iLastSeqNum==endseq) |
|
378 { |
|
379 // No interrupts have occurred that resulted in a new event. |
|
380 iLastSeqNum = lstseq; |
|
381 } |
|
382 else |
|
383 { |
|
384 // New event was generated by the interrupt handler |
|
385 // So extract and zero the inserted count |
|
386 TInt p = ptr; |
|
387 TInt len; |
|
388 TUint s = iInfoPtr[p]; |
|
389 |
|
390 if (s==0) |
|
391 len = endseq-seq; |
|
392 else if ((s & 0x0f)==0x0f) |
|
393 { |
|
394 p = (ptr+0x4)&~0x3; |
|
395 if (p>=iLength) |
|
396 p = 0; |
|
397 len = *((TInt*)(iInfoPtr+p)); |
|
398 *((TInt*)(iInfoPtr+p)) = 0; |
|
399 } |
|
400 else |
|
401 { |
|
402 iInfoPtr[p] &= 0xf0; |
|
403 len = s & 0x0f; |
|
404 } |
|
405 // And in the offset for the last event in the re-scan |
|
406 len += seq-lstseq; |
|
407 // Insert the count into the re-scanned section |
|
408 if (len<0x0f) |
|
409 iInfoPtr[lstptr] = (TUint8)((iInfoPtr[lstptr] & 0xf0) | len); |
|
410 else |
|
411 { |
|
412 iInfoPtr[lstptr] = (TUint8)((iInfoPtr[lstptr] & 0xf0) | 0x0f); |
|
413 // Word align buffer offset and wrap if needed |
|
414 // so a full count can be written |
|
415 p = (lstptr+0x4)&~0x3; |
|
416 if (p>=iLength) |
|
417 p = 0; |
|
418 *((TInt*)(iInfoPtr+p)) = len; |
|
419 } |
|
420 complete = ETrue; |
|
421 } |
|
422 |
|
423 aDriver->EnableInterrupts(); |
|
424 return complete; |
|
425 } |