|
1 // Copyright (c) 2009-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 // e32test\misc\ymodemtx.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include <e32std.h> |
|
19 #include <e32svr.h> |
|
20 #include <f32file.h> |
|
21 #include <d32comm.h> |
|
22 |
|
23 RFs TheFs; |
|
24 RFile TheFile; |
|
25 TInt FileSize; |
|
26 RBusDevComm TheComm; |
|
27 RTimer TheTimer; |
|
28 TFileName FileName; |
|
29 TFileName FileName8b; |
|
30 TPtr8 FileName8(0,0,0); |
|
31 |
|
32 const TUint8 STX=0x02; |
|
33 const TUint8 EOT=0x04; |
|
34 const TUint8 ACK=0x06; |
|
35 const TUint8 BIGC=0x43; |
|
36 const TUint8 BIGG=0x47; |
|
37 |
|
38 #define PACKET_SIZE 1024 |
|
39 |
|
40 #define MIN(a,b) ((a)<(b)?(a):(b)) |
|
41 #define OFFSET(p,off) ((void*)((char*)p+off)) |
|
42 |
|
43 #define RESET_COMM() TheComm.ResetBuffers() |
|
44 |
|
45 #define assert(x) ((void)( (x) || (__Panic(__LINE__, #x),0) )) |
|
46 #define assert_KErrNone(r) ((void)( ((r)==KErrNone) || (__Panic(__LINE__, (r)),0) )) |
|
47 |
|
48 |
|
49 void __Panic(TInt aLine, TInt aError) |
|
50 { |
|
51 RDebug::Printf("Line %d Expected KErrNone got %d", aLine, aError); |
|
52 User::Panic(_L("YMODEMTX"), aLine); |
|
53 } |
|
54 |
|
55 void __Panic(TInt aLine, const char* aMessage) |
|
56 { |
|
57 RDebug::Printf("Line %d Assertion \"%s\" failed", aLine, aMessage); |
|
58 User::Panic(_L("YMODEMTX"), aLine); |
|
59 } |
|
60 |
|
61 /* |
|
62 YModem packet structure: |
|
63 Byte 0 = STX |
|
64 Byte 1 = sequence number (first user data packet is 1) |
|
65 Byte 2 = complement of sequence number |
|
66 Bytes 3-1026 = data (1K per packet) |
|
67 Bytes 1027, 1028 = 16-bit CRC (big-endian) |
|
68 |
|
69 A herald packet is sent first, with sequence number 0 |
|
70 The data field consists of the null-terminated file name |
|
71 followed by the null-terminated file size in ASCII decimal |
|
72 digits. |
|
73 */ |
|
74 struct SPacket |
|
75 { |
|
76 TUint8 iPTI; |
|
77 TUint8 iSeq; |
|
78 TUint8 iSeqBar; |
|
79 TUint8 iData[PACKET_SIZE]; |
|
80 TUint8 iCRC1; |
|
81 TUint8 iCRC0; |
|
82 }; |
|
83 |
|
84 static const TUint16 crcTab[256] = |
|
85 { |
|
86 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,0x8108,0x9129,0xa14a, |
|
87 0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294, |
|
88 0x72f7,0x62d6,0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,0x2462, |
|
89 0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,0xa56a,0xb54b,0x8528,0x9509, |
|
90 0xe5ee,0xf5cf,0xc5ac,0xd58d,0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695, |
|
91 0x46b4,0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,0x48c4,0x58e5, |
|
92 0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948, |
|
93 0x9969,0xa90a,0xb92b,0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, |
|
94 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,0x6ca6,0x7c87,0x4ce4, |
|
95 0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b, |
|
96 0x8d68,0x9d49,0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,0xff9f, |
|
97 0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,0x9188,0x81a9,0xb1ca,0xa1eb, |
|
98 0xd10c,0xc12d,0xf14e,0xe16f,0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046, |
|
99 0x6067,0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,0x02b1,0x1290, |
|
100 0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e, |
|
101 0xe54f,0xd52c,0xc50d,0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, |
|
102 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,0x26d3,0x36f2,0x0691, |
|
103 0x16b0,0x6657,0x7676,0x4615,0x5634,0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9, |
|
104 0xb98a,0xa9ab,0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,0xcb7d, |
|
105 0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,0x4a75,0x5a54,0x6a37,0x7a16, |
|
106 0x0af1,0x1ad0,0x2ab3,0x3a92,0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8, |
|
107 0x8dc9,0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,0xef1f,0xff3e, |
|
108 0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,0x6e17,0x7e36,0x4e55,0x5e74,0x2e93, |
|
109 0x3eb2,0x0ed1,0x1ef0 |
|
110 }; |
|
111 |
|
112 void UpdateCrc(const void* aPtr, TInt aLength, TUint16& aCrc) |
|
113 // |
|
114 // Perform a CCITT CRC checksum. |
|
115 // |
|
116 { |
|
117 |
|
118 register const TUint8* pB = (const TUint8*)aPtr; |
|
119 register TUint16 crc=aCrc; |
|
120 while (aLength--) |
|
121 crc=TUint16((crc<<8)^crcTab[(crc>>8)^*pB++]); |
|
122 aCrc=crc; |
|
123 } |
|
124 |
|
125 void ClearCommError() |
|
126 { |
|
127 } |
|
128 |
|
129 TInt CommRead1(TInt aTimeout) |
|
130 { |
|
131 TBuf8<1> c; |
|
132 TRequestStatus s0, s1; |
|
133 TheComm.ReadOneOrMore(s1, c); |
|
134 TheTimer.After(s0, aTimeout*1000); |
|
135 User::WaitForRequest(s0, s1); |
|
136 if (s1 != KRequestPending) |
|
137 { |
|
138 TheTimer.Cancel(); |
|
139 User::WaitForRequest(s0); |
|
140 return (s1==KErrNone) ? c[0] : s1.Int(); |
|
141 } |
|
142 TheComm.ReadCancel(); |
|
143 User::WaitForRequest(s1); |
|
144 return KErrTimedOut; |
|
145 } |
|
146 |
|
147 TInt CommRead(TDes8& aBuf, TInt aTimeout) |
|
148 { |
|
149 aBuf.Zero(); |
|
150 TRequestStatus s0, s1; |
|
151 TInt timeout = aTimeout * 1000; |
|
152 |
|
153 TUint8* b = (TUint8*)aBuf.Ptr(); |
|
154 while (aBuf.Length() < aBuf.MaxLength()) |
|
155 { |
|
156 TPtr8 p(b+aBuf.Length(), 0, aBuf.MaxLength()-aBuf.Length()); |
|
157 TheComm.ReadOneOrMore(s1, p); |
|
158 TheTimer.After(s0, timeout); |
|
159 User::WaitForRequest(s0, s1); |
|
160 if (s1 == KErrNone) |
|
161 { |
|
162 TheTimer.Cancel(); |
|
163 User::WaitForRequest(s0); |
|
164 aBuf.SetLength(aBuf.Length() + p.Length()); |
|
165 timeout = 500000; |
|
166 continue; |
|
167 } |
|
168 if (s1 != KRequestPending) |
|
169 { |
|
170 TheTimer.Cancel(); |
|
171 User::WaitForRequest(s0); |
|
172 break; |
|
173 } |
|
174 if (s0 != KRequestPending) |
|
175 { |
|
176 TheComm.ReadCancel(); |
|
177 User::WaitForRequest(s1); |
|
178 break; |
|
179 } |
|
180 } |
|
181 if (aBuf.Length()==0) |
|
182 return KErrTimedOut; |
|
183 return aBuf.Length(); |
|
184 } |
|
185 |
|
186 void CommWrite(const TDesC8& aBuf) |
|
187 { |
|
188 TRequestStatus s; |
|
189 TheComm.Write(s, aBuf); |
|
190 User::WaitForRequest(s); |
|
191 } |
|
192 |
|
193 void CommWriteC(TUint aChar) |
|
194 { |
|
195 TBuf8<1> b; |
|
196 b.SetLength(1); |
|
197 b[0] = (TUint8)aChar; |
|
198 CommWrite(b); |
|
199 } |
|
200 |
|
201 void CommWriteS(const char* aString) |
|
202 { |
|
203 CommWrite(TPtrC8((const TUint8*)aString)); |
|
204 } |
|
205 |
|
206 TInt PreparePacket(SPacket& pkt, TInt aSeq) |
|
207 { |
|
208 TInt r = KErrNone; |
|
209 TUint16 crc = 0; |
|
210 |
|
211 pkt.iPTI = STX; |
|
212 pkt.iSeq = (TUint8)(aSeq>=0 ? aSeq : 0); |
|
213 pkt.iSeqBar = (TUint8)~pkt.iSeq; |
|
214 if (aSeq>0) |
|
215 { |
|
216 TInt l; |
|
217 TInt fpos = (aSeq-1)*PACKET_SIZE; // file position of packet |
|
218 if ( fpos >= FileSize ) |
|
219 return KErrEof; |
|
220 l = MIN(PACKET_SIZE, FileSize-fpos); |
|
221 TPtr8 d(pkt.iData, 0, l); |
|
222 assert_KErrNone(TheFile.Read(d)); |
|
223 if (l<PACKET_SIZE) |
|
224 memset(pkt.iData+l, 0, PACKET_SIZE-l); |
|
225 } |
|
226 else |
|
227 { |
|
228 memset(pkt.iData, 0, PACKET_SIZE); |
|
229 if (aSeq==0) |
|
230 { |
|
231 TInt pos = FileName8.LocateReverse('\\'); |
|
232 TPtrC8 fn8(FileName8.Mid(pos+1)); |
|
233 memcpy(pkt.iData, fn8.Ptr(), fn8.Length()); |
|
234 TPtr8 d2(pkt.iData+fn8.Length()+1, 0, PACKET_SIZE-fn8.Length()-1); |
|
235 d2.Num(FileSize); |
|
236 } |
|
237 } |
|
238 UpdateCrc(pkt.iData, PACKET_SIZE, crc); |
|
239 pkt.iCRC1 = (TUint8)(crc>>8); |
|
240 pkt.iCRC0 = (TUint8)crc; |
|
241 return r; |
|
242 } |
|
243 |
|
244 TInt SendPacket(TInt& aSeq, TBool aStream) |
|
245 { |
|
246 TInt c; |
|
247 SPacket pkt; |
|
248 TInt retries = 10; |
|
249 TInt tmout = (aSeq>=0) ? 2000 : 500; |
|
250 TInt r = PreparePacket(pkt, aSeq); |
|
251 if (r!=KErrNone) |
|
252 return r; |
|
253 for(;;) |
|
254 { |
|
255 RESET_COMM(); |
|
256 CommWrite(TPtrC8( (const TUint8*)&pkt, sizeof(pkt) )); |
|
257 if (aStream) |
|
258 break; |
|
259 c = CommRead1(tmout); |
|
260 if (c==KErrTimedOut && aSeq<0) |
|
261 return KErrNone; |
|
262 if (c>=0) |
|
263 { |
|
264 if (c==ACK) |
|
265 break; |
|
266 } |
|
267 if (--retries==0) |
|
268 return KErrTimedOut; |
|
269 } |
|
270 if (aSeq==0) |
|
271 { |
|
272 c = CommRead1(100); |
|
273 if (c==KErrTimedOut) |
|
274 { |
|
275 ++aSeq; |
|
276 return KErrNone; |
|
277 } |
|
278 if (aStream && c!=BIGG) |
|
279 return KErrTimedOut; |
|
280 else if (!aStream && c!=BIGC) |
|
281 return KErrTimedOut; |
|
282 } |
|
283 ++aSeq; |
|
284 return r; |
|
285 } |
|
286 |
|
287 TInt SendImageFile() |
|
288 { |
|
289 TInt r = 0; |
|
290 TInt b1; |
|
291 TBool stream; |
|
292 TInt seq = 0; |
|
293 |
|
294 RESET_COMM(); |
|
295 r = CommRead1(20000); |
|
296 if (r<0) |
|
297 return r; |
|
298 if (r!=BIGG && r!=BIGC) |
|
299 return KErrTimedOut; |
|
300 stream = (r==BIGG); |
|
301 seq = 0; |
|
302 r = KErrNone; |
|
303 while (r==KErrNone) |
|
304 { |
|
305 r = SendPacket(seq, stream); |
|
306 } |
|
307 if (r!=KErrEof) |
|
308 return r; |
|
309 r=KErrNone; |
|
310 RESET_COMM(); |
|
311 CommWriteC(EOT); |
|
312 b1 = CommRead1(500); |
|
313 if (b1==KErrTimedOut) |
|
314 return KErrNone; |
|
315 if (b1!=ACK) |
|
316 return KErrNone; |
|
317 b1 = CommRead1(1000); |
|
318 if (b1==KErrTimedOut) |
|
319 return KErrNone; |
|
320 if (stream && b1!=BIGG) |
|
321 return KErrNone; |
|
322 else if (!stream && b1!=BIGC) |
|
323 return KErrNone; |
|
324 seq = -1; |
|
325 r = SendPacket(seq, stream); |
|
326 return r; |
|
327 } |
|
328 |
|
329 |
|
330 #define ALLOWBPS(x) case x : bps = EBps##x; break |
|
331 |
|
332 void ParseCommandLine() |
|
333 { |
|
334 TInt r = 0; |
|
335 TInt cmdLineLen = User::CommandLineLength(); |
|
336 HBufC* cmdLine = HBufC::New(cmdLineLen); |
|
337 assert(cmdLine!=0); |
|
338 TPtr cmdLineW(cmdLine->Des()); |
|
339 User::CommandLine(cmdLineW); |
|
340 TLex16 cmdLineLex(*cmdLine); |
|
341 TInt baud = 115200; |
|
342 TInt port = 0; |
|
343 while (!cmdLineLex.Eos()) |
|
344 { |
|
345 TPtrC token(cmdLineLex.NextToken()); |
|
346 cmdLineLex.SkipSpace(); |
|
347 if (token[0]=='-') |
|
348 { |
|
349 switch (token[1]) |
|
350 { |
|
351 case 'p': |
|
352 { |
|
353 r = cmdLineLex.Val(port); |
|
354 assert_KErrNone(r); |
|
355 break; |
|
356 } |
|
357 case 'b': |
|
358 { |
|
359 r = cmdLineLex.Val(baud); |
|
360 assert_KErrNone(r); |
|
361 break; |
|
362 } |
|
363 default: |
|
364 assert(0); |
|
365 break; |
|
366 } |
|
367 continue; |
|
368 } |
|
369 FileName = token; |
|
370 assert(cmdLineLex.Eos()); |
|
371 } |
|
372 assert(FileName.Length()>0); |
|
373 |
|
374 TBps bps = EBpsSpecial; |
|
375 switch (baud) |
|
376 { |
|
377 ALLOWBPS(50); |
|
378 ALLOWBPS(75); |
|
379 ALLOWBPS(110); |
|
380 ALLOWBPS(134); |
|
381 ALLOWBPS(150); |
|
382 ALLOWBPS(300); |
|
383 ALLOWBPS(600); |
|
384 ALLOWBPS(1200); |
|
385 ALLOWBPS(1800); |
|
386 ALLOWBPS(2000); |
|
387 ALLOWBPS(2400); |
|
388 ALLOWBPS(3600); |
|
389 ALLOWBPS(4800); |
|
390 ALLOWBPS(7200); |
|
391 ALLOWBPS(9600); |
|
392 ALLOWBPS(19200); |
|
393 ALLOWBPS(38400); |
|
394 ALLOWBPS(57600); |
|
395 ALLOWBPS(115200); |
|
396 ALLOWBPS(230400); |
|
397 ALLOWBPS(460800); |
|
398 ALLOWBPS(576000); |
|
399 ALLOWBPS(1152000); |
|
400 ALLOWBPS(4000000); |
|
401 ALLOWBPS(921600); |
|
402 } |
|
403 assert(bps != EBpsSpecial); |
|
404 |
|
405 assert_KErrNone(TheFs.Connect()); |
|
406 assert_KErrNone(TheFile.Open(TheFs, FileName, EFileShareReadersOnly|EFileRead)); |
|
407 assert_KErrNone(TheFile.Size(FileSize)); |
|
408 FileName8b = FileName; |
|
409 new (&FileName8) TPtr8(FileName8b.Collapse()); |
|
410 assert(TheComm.Open(port)==KErrNone); |
|
411 TCommConfig cfgBuf; |
|
412 TCommConfigV01& cfg = cfgBuf(); |
|
413 cfg.iRate = bps; |
|
414 cfg.iDataBits = EData8; |
|
415 cfg.iStopBits = EStop1; |
|
416 cfg.iParity = EParityNone; |
|
417 cfg.iHandshake = 0; |
|
418 cfg.iParityError = 0; |
|
419 cfg.iFifo = EFifoEnable; |
|
420 cfg.iSpecialRate = 0; |
|
421 cfg.iTerminatorCount = 0; |
|
422 cfg.iSIREnable = ESIRDisable; |
|
423 cfg.iSIRSettings = KConfigSIRShutDown; |
|
424 assert_KErrNone(TheComm.SetConfig(cfgBuf)); |
|
425 CommWrite(_L8("Sending ")); |
|
426 CommWrite(FileName8); |
|
427 CommWrite(_L8("\r\nWaiting for YModem or YModem-G receive...\r\n")); |
|
428 } |
|
429 |
|
430 _LIT(KLddName,"ECOMM"); |
|
431 _LIT(KPddName,"EUART"); |
|
432 |
|
433 void LoadCommDrivers() |
|
434 { |
|
435 TInt r=User::LoadLogicalDevice(KLddName); |
|
436 if (r!=KErrAlreadyExists) |
|
437 assert_KErrNone(r); |
|
438 |
|
439 TInt i; |
|
440 TInt n=0; |
|
441 for (i=-1; i<10; ++i) |
|
442 { |
|
443 TBuf<16> pddName=KPddName(); |
|
444 if (i>=0) |
|
445 pddName.Append('0'+i); |
|
446 r=User::LoadPhysicalDevice(pddName); |
|
447 if (r==KErrNone || r==KErrAlreadyExists) |
|
448 ++n; |
|
449 } |
|
450 assert(n!=0); |
|
451 } |
|
452 |
|
453 TInt E32Main() |
|
454 { |
|
455 TInt r; |
|
456 |
|
457 LoadCommDrivers(); |
|
458 ParseCommandLine(); |
|
459 |
|
460 r = TheTimer.CreateLocal(); |
|
461 assert_KErrNone(r); |
|
462 |
|
463 r = SendImageFile(); |
|
464 assert_KErrNone(r); |
|
465 |
|
466 TheTimer.Close(); |
|
467 TheComm.Close(); |
|
468 TheFile.Close(); |
|
469 TheFs.Close(); |
|
470 |
|
471 return KErrNone; |
|
472 } |