|
1 /* |
|
2 * Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * e32utils\trgtest\trgtesth.cpp |
|
16 * |
|
17 */ |
|
18 |
|
19 |
|
20 #include <e32err.h> |
|
21 #include <windows.h> |
|
22 #include <shlwapi.h> |
|
23 #include <stdio.h> |
|
24 #include <time.h> |
|
25 |
|
26 #pragma comment(lib, "shlwapi.lib") |
|
27 |
|
28 const TUint8 SOH=0x01; |
|
29 const TUint8 STX=0x02; |
|
30 const TUint8 EOT=0x04; |
|
31 const TUint8 ACK=0x06; |
|
32 const TUint8 NAK=0x15; |
|
33 const TUint8 CAN=0x18; |
|
34 const TUint8 SUB=0x1A; |
|
35 const TUint8 BIGC=0x43; |
|
36 const TUint8 BIGG=0x47; |
|
37 |
|
38 // Try 115200bps first since it is the most commonly supported baud rate. Newer platforms like the |
|
39 // NaviEngine support 230400bps and above. |
|
40 const TUint KDefaultBaudRate = 115200; |
|
41 const TUint KBaudRateSearchList[] = {KDefaultBaudRate, 230400, 460800}; |
|
42 |
|
43 #define READ_BUF_SIZE 32768 |
|
44 #define WRITE_BUF_SIZE 32768 |
|
45 #define MAX_LINE 32768 |
|
46 #define PACKET_SIZE 1024 |
|
47 |
|
48 #define MIN(a,b) ((a)<(b)?(a):(b)) |
|
49 #define OFFSET(p,off) ((void*)((char*)p+off)) |
|
50 |
|
51 #define RESET_COMM() PurgeComm(Comm, PURGE_RXCLEAR|PURGE_TXCLEAR) |
|
52 |
|
53 const TInt KExitCodeOK = 0; // no failure |
|
54 const TInt KExitCodeUsage = 1; // command like usage |
|
55 const TInt KExitCodeLog = 2; // can't open log file |
|
56 const TInt KExitCodeImage = 3; // can't open image file |
|
57 const TInt KExitCodeSerial = 4; // can't open serial port |
|
58 const TInt KExitCodeDownload = 5; // download started, but failed |
|
59 const TInt KExitCodeFaulted = 6; // entered debug monitor abnormally |
|
60 const TInt KExitCodeHung = 7; // target hung |
|
61 const TInt KExitCodeDOA = 8; // board was in debug monitor at start |
|
62 const TInt KExitCodeUnsupportedBaudRate = 9; // the baud rate set by the -b parameter is not supported by the PC's COM port |
|
63 const TInt KExitCodeAssert = 99; // trgtest assertion failed |
|
64 |
|
65 FILE* LogFile = NULL; |
|
66 HANDLE Comm = INVALID_HANDLE_VALUE; |
|
67 |
|
68 char ImgFileName[MAX_PATH] = ""; |
|
69 TInt ImgFileSize = 0; |
|
70 char LineBuf[MAX_LINE+1]; |
|
71 void* ImgFileChunkBase = NULL; |
|
72 TBool use_stdout = false; |
|
73 |
|
74 enum EDebugMonitorOptions |
|
75 { |
|
76 kDebugDumpCodeSegs = 1 |
|
77 }; |
|
78 |
|
79 TUint DebugMonitorOptions = kDebugDumpCodeSegs; |
|
80 |
|
81 #define TT_ASSERT(x) __ASSERT_ALWAYS(x, __Panic(__LINE__)) |
|
82 |
|
83 const char* GetWinErrMsg(DWORD errorCode) |
|
84 { |
|
85 static char lastErrorBuffer[512]; // not thread safe or reentrant (but shouldn't need to be) |
|
86 strcpy(lastErrorBuffer, "Unknown error"); |
|
87 |
|
88 if(errorCode != ERROR_SUCCESS) |
|
89 { |
|
90 if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode, 0, lastErrorBuffer, 512, NULL) != 0) |
|
91 { |
|
92 size_t size = strlen(lastErrorBuffer); |
|
93 |
|
94 // Strip any trailing carriage return. |
|
95 if(StrCmpNI(lastErrorBuffer + size - 2, "\r\n", 2) == 0) |
|
96 { |
|
97 lastErrorBuffer[size - 2] = '\0'; |
|
98 size -= 2; |
|
99 } |
|
100 |
|
101 // Strip any trailing period. |
|
102 if(lastErrorBuffer[size - 1] == '.') |
|
103 { |
|
104 lastErrorBuffer[size - 1] = '\0'; |
|
105 } |
|
106 } |
|
107 } |
|
108 |
|
109 return lastErrorBuffer; |
|
110 } |
|
111 |
|
112 const char* GetSymOrWinErrMsg(TInt errorCode) |
|
113 { |
|
114 static char lastErrorBuffer[512]; // not thread safe or reentrant (but shouldn't need to be) |
|
115 strcpy(lastErrorBuffer, "Unknown error"); |
|
116 |
|
117 switch(errorCode) |
|
118 { |
|
119 case KErrNone: |
|
120 { |
|
121 // Unknown error |
|
122 } |
|
123 break; |
|
124 case KErrEof: |
|
125 { |
|
126 strcpy(lastErrorBuffer, "Unexpected end of file"); |
|
127 } |
|
128 break; |
|
129 case KErrTimedOut: |
|
130 { |
|
131 strcpy(lastErrorBuffer, "Timed-out"); |
|
132 } |
|
133 break; |
|
134 default: |
|
135 { |
|
136 if(errorCode > 0) |
|
137 { |
|
138 strcpy(lastErrorBuffer, GetWinErrMsg(errorCode)); |
|
139 } |
|
140 } |
|
141 break; |
|
142 } |
|
143 |
|
144 return lastErrorBuffer; |
|
145 } |
|
146 |
|
147 void __Panic(TInt aLine) |
|
148 { |
|
149 fprintf(stderr, "Assertion failed at line %d\n", aLine); |
|
150 exit(KExitCodeAssert); |
|
151 } |
|
152 |
|
153 void WriteLog(const void* aBuf, TInt aLength) |
|
154 { |
|
155 if (LogFile) |
|
156 fwrite(aBuf, 1, aLength, LogFile); |
|
157 } |
|
158 |
|
159 void WriteLogS(const char* aString) |
|
160 { |
|
161 WriteLog( aString, strlen(aString) ); |
|
162 } |
|
163 |
|
164 void TraceLog(const char* aFmt, ...) |
|
165 { |
|
166 char buf[512]; |
|
167 va_list list; |
|
168 va_start(list, aFmt); |
|
169 if (!LogFile) |
|
170 return; |
|
171 sprintf(buf, "TRGTEST: "); |
|
172 vsprintf(buf, aFmt, list); |
|
173 strcat(buf, "\r\n"); |
|
174 WriteLogS(buf); |
|
175 } |
|
176 |
|
177 /* |
|
178 YModem packet structure: |
|
179 Byte 0 = STX |
|
180 Byte 1 = sequence number (first user data packet is 1) |
|
181 Byte 2 = complement of sequence number |
|
182 Bytes 3-1026 = data (1K per packet) |
|
183 Bytes 1027, 1028 = 16-bit CRC (big-endian) |
|
184 |
|
185 A herald packet is sent first, with sequence number 0 |
|
186 The data field consists of the null-terminated file name |
|
187 followed by the null-terminated file size in ASCII decimal |
|
188 digits. |
|
189 */ |
|
190 struct SPacket |
|
191 { |
|
192 TUint8 iPTI; |
|
193 TUint8 iSeq; |
|
194 TUint8 iSeqBar; |
|
195 TUint8 iData[PACKET_SIZE]; |
|
196 TUint8 iCRC1; |
|
197 TUint8 iCRC0; |
|
198 }; |
|
199 |
|
200 static const TUint16 crcTab[256] = |
|
201 { |
|
202 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,0x8108,0x9129,0xa14a, |
|
203 0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294, |
|
204 0x72f7,0x62d6,0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,0x2462, |
|
205 0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,0xa56a,0xb54b,0x8528,0x9509, |
|
206 0xe5ee,0xf5cf,0xc5ac,0xd58d,0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695, |
|
207 0x46b4,0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,0x48c4,0x58e5, |
|
208 0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948, |
|
209 0x9969,0xa90a,0xb92b,0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, |
|
210 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,0x6ca6,0x7c87,0x4ce4, |
|
211 0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b, |
|
212 0x8d68,0x9d49,0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,0xff9f, |
|
213 0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,0x9188,0x81a9,0xb1ca,0xa1eb, |
|
214 0xd10c,0xc12d,0xf14e,0xe16f,0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046, |
|
215 0x6067,0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,0x02b1,0x1290, |
|
216 0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e, |
|
217 0xe54f,0xd52c,0xc50d,0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, |
|
218 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,0x26d3,0x36f2,0x0691, |
|
219 0x16b0,0x6657,0x7676,0x4615,0x5634,0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9, |
|
220 0xb98a,0xa9ab,0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,0xcb7d, |
|
221 0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,0x4a75,0x5a54,0x6a37,0x7a16, |
|
222 0x0af1,0x1ad0,0x2ab3,0x3a92,0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8, |
|
223 0x8dc9,0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,0xef1f,0xff3e, |
|
224 0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,0x6e17,0x7e36,0x4e55,0x5e74,0x2e93, |
|
225 0x3eb2,0x0ed1,0x1ef0 |
|
226 }; |
|
227 |
|
228 void UpdateCrc(const void* aPtr, TInt aLength, TUint16& aCrc) |
|
229 // |
|
230 // Perform a CCITT CRC checksum. |
|
231 // |
|
232 { |
|
233 |
|
234 register const TUint8* pB = (const TUint8*)aPtr; |
|
235 register TUint16 crc=aCrc; |
|
236 while (aLength--) |
|
237 crc=TUint16((crc<<8)^crcTab[(crc>>8)^*pB++]); |
|
238 aCrc=crc; |
|
239 } |
|
240 |
|
241 void ClearCommError() |
|
242 { |
|
243 DWORD err; |
|
244 COMSTAT s; |
|
245 TT_ASSERT(ClearCommError(Comm,&err,&s)); |
|
246 } |
|
247 |
|
248 void OpenCommPort(TInt aPort) |
|
249 { |
|
250 char buf[20]; |
|
251 |
|
252 sprintf(buf, "\\\\.\\COM%d", aPort); // COM ports with indexes higher than 9 can only be referenced by prefixing the device name with "\\.\\" |
|
253 Comm = CreateFile(buf, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); |
|
254 if (Comm == INVALID_HANDLE_VALUE) |
|
255 { |
|
256 if(GetLastError() == ERROR_ACCESS_DENIED) |
|
257 { |
|
258 fprintf(stderr, "Can't open COM%d: Error %d (Access denied) - a terminal application has probably been left running with the port still open\n", aPort, ERROR_ACCESS_DENIED); |
|
259 } |
|
260 else |
|
261 { |
|
262 fprintf(stderr, "Can't open COM%d: Error %d (%s)\n", aPort, GetLastError(), GetWinErrMsg(GetLastError())); |
|
263 } |
|
264 exit(KExitCodeSerial); |
|
265 } |
|
266 |
|
267 // Raise our thread priority to avoid being starved if builds are continuing in parallel while we are communicating with the target |
|
268 // at high speeds. TrgTest does not use serial flow control so if the buffers fill up, data will be lost. We do not try to use the |
|
269 // real-time process priority class because it requires administrator privileges. |
|
270 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); |
|
271 } |
|
272 |
|
273 TInt SetupCommPort(TInt aPort, TUint aBaudRate, TBool aIgnoreInvalidBaudRateError = false) |
|
274 { |
|
275 TInt r = KErrNone; |
|
276 const char* errFuncName = NULL; |
|
277 |
|
278 DCB dcb; |
|
279 |
|
280 dcb.DCBlength = sizeof(dcb); |
|
281 if(!GetCommState(Comm, &dcb)) |
|
282 { |
|
283 r = GetLastError(); |
|
284 errFuncName = "GetCommState"; |
|
285 } |
|
286 else if(!SetCommMask(Comm, EV_ERR|EV_RXCHAR)) |
|
287 { |
|
288 r = GetLastError(); |
|
289 errFuncName = "SetCommMask"; |
|
290 } |
|
291 else if(!SetupComm(Comm, READ_BUF_SIZE, WRITE_BUF_SIZE)) |
|
292 { |
|
293 r = GetLastError(); |
|
294 errFuncName = "SetupComm"; |
|
295 } |
|
296 if(r != KErrNone) |
|
297 { |
|
298 TT_ASSERT(errFuncName); |
|
299 |
|
300 fprintf(stderr, "Error in SetupComm: Error %d (%s) calling %s\n", r, GetWinErrMsg(r), errFuncName); |
|
301 TraceLog("Error in SetupComm: Error %d (%s) calling %s", r, GetWinErrMsg(r), errFuncName); |
|
302 fprintf(stderr, "Trying to proceed anyway, be suspicious of any problems!\n"); |
|
303 TraceLog("Trying to proceed anyway, be suspicious of any problems!"); |
|
304 } |
|
305 ClearCommError(); |
|
306 r = KErrNone; |
|
307 |
|
308 dcb.fAbortOnError = TRUE; |
|
309 dcb.BaudRate=aBaudRate; |
|
310 dcb.Parity=NOPARITY; |
|
311 dcb.fParity = FALSE; |
|
312 dcb.fErrorChar = FALSE; |
|
313 dcb.ByteSize = 8; |
|
314 dcb.StopBits=ONESTOPBIT; |
|
315 dcb.fInX = FALSE; |
|
316 dcb.fOutX = FALSE; |
|
317 dcb.XonChar = 0; |
|
318 dcb.XoffChar = 0; |
|
319 dcb.ErrorChar = 0; |
|
320 dcb.fOutxDsrFlow = FALSE; |
|
321 dcb.fOutxCtsFlow = FALSE; |
|
322 dcb.fDsrSensitivity = FALSE; |
|
323 dcb.fRtsControl = RTS_CONTROL_DISABLE; |
|
324 dcb.fDtrControl = DTR_CONTROL_DISABLE; |
|
325 if(!SetCommState(Comm, &dcb)) |
|
326 { |
|
327 if(GetLastError() == ERROR_INVALID_PARAMETER) |
|
328 { |
|
329 r = KExitCodeUnsupportedBaudRate; |
|
330 |
|
331 if(aIgnoreInvalidBaudRateError) |
|
332 { |
|
333 return r; |
|
334 } |
|
335 else |
|
336 { |
|
337 fprintf(stderr, "Error in SetCommState : Error %d (%s) - a baud rate of %dbps is not supported by COM%d - try a different port\n", GetLastError(), GetWinErrMsg(GetLastError()), aBaudRate, aPort); |
|
338 TraceLog("Error in SetCommState : Error %d (%s) - a baud rate of %dbps is not supported by COM%d - try a different port", GetLastError(), GetWinErrMsg(GetLastError()), aBaudRate, aPort); |
|
339 } |
|
340 } |
|
341 else |
|
342 { |
|
343 fprintf(stderr, "Error in SetCommState : Error %d calling (%s) SetCommState\n", GetLastError(), GetWinErrMsg(GetLastError()), aBaudRate); |
|
344 TraceLog("Error in SetCommState : Error %d (%s) SetCommState", GetLastError(), GetWinErrMsg(GetLastError()), aBaudRate); |
|
345 r = KExitCodeSerial; |
|
346 } |
|
347 |
|
348 exit(r); |
|
349 } |
|
350 EscapeCommFunction(Comm, SETDTR); |
|
351 EscapeCommFunction(Comm, SETRTS); |
|
352 |
|
353 return KErrNone; |
|
354 } |
|
355 |
|
356 void SetupTimeout(TInt aInt, TInt aTot) |
|
357 { |
|
358 COMMTIMEOUTS ct; |
|
359 GetCommTimeouts(Comm, &ct); |
|
360 ct.ReadIntervalTimeout = aInt; // ms |
|
361 ct.ReadTotalTimeoutMultiplier = 0; |
|
362 ct.ReadTotalTimeoutConstant = aTot; // ms |
|
363 ct.WriteTotalTimeoutConstant = 0; |
|
364 ct.WriteTotalTimeoutMultiplier = 0; |
|
365 SetCommTimeouts(Comm, &ct); |
|
366 } |
|
367 |
|
368 TInt CommRead1(TInt aTimeout) |
|
369 { |
|
370 unsigned char c; |
|
371 DWORD n=0; |
|
372 BOOL ok; |
|
373 |
|
374 SetupTimeout(0, aTimeout); |
|
375 ok = ReadFile(Comm, &c, 1, &n, NULL); |
|
376 if (!ok) |
|
377 ClearCommError(); |
|
378 if (ok && n) |
|
379 return c; |
|
380 return KErrTimedOut; |
|
381 } |
|
382 |
|
383 TInt CommRead(void* aBuf, TInt aMax, TInt aTimeout) |
|
384 { |
|
385 DWORD n=0; |
|
386 BOOL ok; |
|
387 |
|
388 SetupTimeout(100, aTimeout); |
|
389 ok = ReadFile(Comm, aBuf, aMax, &n, NULL); |
|
390 if (!ok) |
|
391 ClearCommError(); |
|
392 if (n==0) |
|
393 return KErrTimedOut; |
|
394 return n; |
|
395 } |
|
396 |
|
397 void CommWrite(const void* aBuf, TInt aLen) |
|
398 { |
|
399 DWORD n = 0; |
|
400 BOOL ok = WriteFile(Comm, aBuf, aLen, &n, NULL); |
|
401 if (!ok) |
|
402 ClearCommError(); |
|
403 } |
|
404 |
|
405 void CommWriteC(TUint aChar) |
|
406 { |
|
407 unsigned char c = (unsigned char)aChar; |
|
408 CommWrite(&c, 1); |
|
409 } |
|
410 |
|
411 void CommWriteS(const char* aString) |
|
412 { |
|
413 CommWrite( aString, strlen(aString) ); |
|
414 } |
|
415 |
|
416 TInt PreparePacket(SPacket& pkt, TInt aSeq, TInt& aOutBytesUploaded) |
|
417 { |
|
418 TInt r = KErrNone; |
|
419 TUint16 crc = 0; |
|
420 |
|
421 pkt.iPTI = STX; |
|
422 pkt.iSeq = (TUint8)(aSeq>=0 ? aSeq : 0); |
|
423 pkt.iSeqBar = (TUint8)~pkt.iSeq; |
|
424 if (aSeq>0) |
|
425 { |
|
426 TInt l; |
|
427 aOutBytesUploaded = (aSeq-1)*PACKET_SIZE; // file position of packet |
|
428 if ( aOutBytesUploaded >= ImgFileSize ) |
|
429 return KErrEof; |
|
430 l = MIN(PACKET_SIZE, ImgFileSize-aOutBytesUploaded); |
|
431 memcpy(pkt.iData, OFFSET(ImgFileChunkBase,aOutBytesUploaded), l); |
|
432 if (l<PACKET_SIZE) |
|
433 memset(pkt.iData+l, 0, PACKET_SIZE-l); |
|
434 aOutBytesUploaded = max( aOutBytesUploaded, 0L ); |
|
435 } |
|
436 else |
|
437 { |
|
438 aOutBytesUploaded = 0; |
|
439 memset(pkt.iData, 0, PACKET_SIZE); |
|
440 if (aSeq==0) |
|
441 { |
|
442 const char* p = ImgFileName; |
|
443 const char* q = p + strlen(p); |
|
444 while (--q>=p && *q!='\\') {} |
|
445 sprintf( (char*)pkt.iData, "%s%c%d", q+1, 0, ImgFileSize); |
|
446 } |
|
447 } |
|
448 UpdateCrc(pkt.iData, PACKET_SIZE, crc); |
|
449 pkt.iCRC1 = (TUint8)(crc>>8); |
|
450 pkt.iCRC0 = (TUint8)crc; |
|
451 return r; |
|
452 } |
|
453 |
|
454 TInt SendPacket(TInt& aSeq, TBool aStream, clock_t startTime) |
|
455 { |
|
456 TBool ackPacket = aSeq == -1; |
|
457 TInt c; |
|
458 SPacket pkt; |
|
459 TInt retries = 10; |
|
460 TInt tmout = (aSeq>=0) ? 2000 : 500; |
|
461 TInt bytesUploaded; |
|
462 |
|
463 // Prepare the next packet. |
|
464 TInt r = PreparePacket(pkt, aSeq, bytesUploaded); |
|
465 |
|
466 if (r==KErrNone) |
|
467 { |
|
468 // Keep trying to send the packet until it is acknowledged. |
|
469 for(;;) |
|
470 { |
|
471 RESET_COMM(); |
|
472 CommWrite(&pkt, sizeof(pkt)); |
|
473 if (aStream) |
|
474 break; |
|
475 c = CommRead1(tmout); |
|
476 if (c==KErrTimedOut && aSeq<0) |
|
477 { |
|
478 return KErrNone; |
|
479 } |
|
480 if (c>=0) |
|
481 { |
|
482 if (c==ACK) |
|
483 break; |
|
484 } |
|
485 if (--retries==0) |
|
486 { |
|
487 r = KErrTimedOut; |
|
488 break; |
|
489 } |
|
490 } |
|
491 |
|
492 // Check to see if the send operation was successful. |
|
493 if (r == KErrNone || (r == KErrEof)) |
|
494 { |
|
495 // Verify the stream type for the first packet. |
|
496 if(aSeq==0) |
|
497 { |
|
498 c = CommRead1(100); |
|
499 if (c==KErrTimedOut) |
|
500 { |
|
501 r = KErrNone; |
|
502 } |
|
503 else if (aStream && c!=BIGG) |
|
504 r = KErrTimedOut; |
|
505 else if (!aStream && c!=BIGC) |
|
506 r = KErrTimedOut; |
|
507 } |
|
508 |
|
509 if(r == KErrNone) |
|
510 { |
|
511 ++aSeq; |
|
512 } |
|
513 } |
|
514 } |
|
515 |
|
516 // Print the progress info. |
|
517 if (((r == KErrNone) && ((aSeq & 7) == 0)) || (r != KErrNone) || ackPacket) |
|
518 { |
|
519 // Calculate total packet count. |
|
520 TInt totalPacketCount = (ImgFileSize / PACKET_SIZE) + 2; // one extra packet for handshake and one extra packet for acknowledgement |
|
521 TInt roundedImageFileSize = ImgFileSize; |
|
522 TInt remainderSize = ImgFileSize % PACKET_SIZE; |
|
523 if(remainderSize != 0) |
|
524 { |
|
525 totalPacketCount ++; |
|
526 roundedImageFileSize += (PACKET_SIZE - remainderSize); |
|
527 } |
|
528 |
|
529 // Calculate the percentage complete. |
|
530 TInt percentComplete = (bytesUploaded * 100) / roundedImageFileSize; |
|
531 |
|
532 // Calculate the ETA. |
|
533 clock_t elapsedTime = clock() - startTime; |
|
534 clock_t etaM = -1L; |
|
535 clock_t etaS = -1L; |
|
536 if(aSeq > 0) |
|
537 { |
|
538 double bytesPerSec = double(bytesUploaded) / (double(elapsedTime) / double(CLOCKS_PER_SEC)); |
|
539 clock_t etaTotalS = clock_t((double(roundedImageFileSize) - double(bytesUploaded)) / bytesPerSec); |
|
540 etaM = max(etaTotalS / 60, 0L); |
|
541 etaS = max(etaTotalS % 60, 0L); |
|
542 } |
|
543 |
|
544 // Ensure upload always halts at 100%. |
|
545 if(ackPacket) |
|
546 { |
|
547 aSeq = totalPacketCount; |
|
548 bytesUploaded = roundedImageFileSize; |
|
549 percentComplete = 100; |
|
550 etaM = 0L; |
|
551 etaS = 0L; |
|
552 } |
|
553 |
|
554 // Format uploaded bytes and ROM size. |
|
555 char sizeBuffer[256]; |
|
556 StrFormatByteSize(bytesUploaded, sizeBuffer, sizeof(sizeBuffer)); |
|
557 char imageSizeBuffer[256]; |
|
558 StrFormatByteSize(roundedImageFileSize, imageSizeBuffer, sizeof(imageSizeBuffer)); |
|
559 |
|
560 // Update the currently uploaded bytes, percentage complete and ETA in-place. |
|
561 // We add additional spacing to overwrite the previous line if the new line |
|
562 // contracts because the byte sizes have switched to larger units. |
|
563 if(ackPacket) |
|
564 { |
|
565 elapsedTime /= CLOCKS_PER_SEC; |
|
566 clock_t elapsedM = max(elapsedTime / 60, 0L); |
|
567 clock_t elapsedS = max(elapsedTime % 60, 0L); |
|
568 printf("\r%05d Packets Sent: %s / %s (%02d %%), Time Taken: %02d:%02d ", aSeq, sizeBuffer, imageSizeBuffer, percentComplete, elapsedM, elapsedS); |
|
569 } |
|
570 else if((r == KErrNone) || (r == KErrEof)) |
|
571 { |
|
572 if(etaM >= 0L) |
|
573 { |
|
574 printf("\r%05d Packets Sent: %s / %s (%02d %%), ETA: %02d:%02d ", aSeq, sizeBuffer, imageSizeBuffer, percentComplete, etaM, etaS); |
|
575 } |
|
576 else |
|
577 { |
|
578 printf("\r%05d Packets Sent: %s / %s (%02d %%), ETA: ??:?? ", aSeq, sizeBuffer, imageSizeBuffer, percentComplete); |
|
579 } |
|
580 } |
|
581 else |
|
582 { |
|
583 fprintf(stderr, "\rFailed to send packet %d: %s / %s (%02d %%), Error: %d (%s) ", ackPacket ? (totalPacketCount - 1) : aSeq, sizeBuffer, imageSizeBuffer, percentComplete, r, GetSymOrWinErrMsg(r)); |
|
584 } |
|
585 } |
|
586 |
|
587 return r; |
|
588 } |
|
589 |
|
590 TInt GetMonitorInfo(); |
|
591 |
|
592 TInt Handshake(TBool& aOutStream, TBool aIgnoreHandshakeFailure = false) |
|
593 { |
|
594 TInt r = 0; |
|
595 TInt r2 = 0; |
|
596 TUint8 b2[256]; |
|
597 |
|
598 Sleep(2000); // wait 2 seconds |
|
599 RESET_COMM(); |
|
600 Sleep(2000); // wait 2 seconds |
|
601 flush: |
|
602 r = CommRead(b2, sizeof(b2), 60000); // 60 second timeout |
|
603 if(r==sizeof(b2)) |
|
604 { |
|
605 printf("Flushing data from port\n"); |
|
606 TraceLog("Flushing data from port"); |
|
607 goto flush; |
|
608 } |
|
609 |
|
610 if (r<0) |
|
611 { |
|
612 TraceLog("ERROR Handshake 1: r=%d (%s)", r, GetSymOrWinErrMsg(r)); |
|
613 // Send CR to see if it elicits monitor prompt |
|
614 CommWriteC(0x0d); |
|
615 r2 = CommRead(LineBuf, 12, 1000); // 1 second timeout |
|
616 if (r2==12 && memcmp(LineBuf, "\xd\xaPassword: ", 12)==0) |
|
617 { |
|
618 printf("ERROR: target is in debug monitor\n"); |
|
619 TraceLog("ERROR: target is in debug monitor"); |
|
620 if (LogFile) |
|
621 { |
|
622 printf("Gathering information...\n"); |
|
623 TraceLog("Gathering information..."); |
|
624 r2 = GetMonitorInfo(); |
|
625 printf("Rebooting...\n"); |
|
626 TraceLog("Rebooting..."); |
|
627 CommWriteS("X\xd"); |
|
628 } |
|
629 else |
|
630 { |
|
631 printf("No logfile - preserving state (not rebooting)\n"); |
|
632 TraceLog("No logfile - preserving state (not rebooting)"); |
|
633 } |
|
634 return KExitCodeDOA; |
|
635 } |
|
636 return r; |
|
637 } |
|
638 if (b2[r-1]!=BIGG && b2[r-1]!=BIGC) |
|
639 { |
|
640 if(!aIgnoreHandshakeFailure) |
|
641 { |
|
642 TraceLog("ERROR Handshake 2: r=%d (%s)", KErrTimedOut, GetSymOrWinErrMsg(KErrTimedOut)); |
|
643 } |
|
644 return KErrTimedOut; |
|
645 } |
|
646 |
|
647 aOutStream = (b2[r-1]==BIGG); |
|
648 |
|
649 return KErrNone; |
|
650 } |
|
651 |
|
652 TInt SendImageFile(TUint aPort, TUint aBaudRate, TBool aStream) |
|
653 { |
|
654 printf("Sending ROM image %s on COM%d at %dbps\n",ImgFileName,aPort,aBaudRate); |
|
655 TraceLog("Sending ROM image %s on COM%d at %dbps",ImgFileName,aPort,aBaudRate); |
|
656 |
|
657 TInt r = KErrNone; |
|
658 |
|
659 // Keep sending packets until we reach the end of the file or an error occurs. |
|
660 TInt seq = 0; |
|
661 clock_t startTime = clock(); |
|
662 while(r==KErrNone) |
|
663 { |
|
664 r = SendPacket(seq, aStream, startTime); |
|
665 } |
|
666 |
|
667 // If we reached the end of the file, acknowledge that the transfer is complete. |
|
668 if(r==KErrEof) |
|
669 { |
|
670 RESET_COMM(); |
|
671 CommWriteC(EOT); |
|
672 TInt b1 = CommRead1(500); |
|
673 if (b1==KErrTimedOut) |
|
674 { |
|
675 r = KErrNone; |
|
676 } |
|
677 else if (b1!=ACK) |
|
678 { |
|
679 r = KErrNone; |
|
680 } |
|
681 |
|
682 if(r == KErrNone) |
|
683 { |
|
684 printf("\n"); |
|
685 } |
|
686 else |
|
687 { |
|
688 // Wait for acknowledgement from the target. |
|
689 TBool noAck = false; |
|
690 b1 = CommRead1(1000); |
|
691 if (b1==KErrTimedOut) |
|
692 { |
|
693 r = KErrNone; |
|
694 noAck = true; |
|
695 } |
|
696 else if (aStream && b1!=BIGG) |
|
697 { |
|
698 r = KErrNone; |
|
699 noAck = true; |
|
700 } |
|
701 else if (!aStream && b1!=BIGC) |
|
702 { |
|
703 r = KErrNone; |
|
704 noAck = true; |
|
705 } |
|
706 |
|
707 // If there was no acknowledgement from the target, ignore the problem at this point and print the newline. |
|
708 if(noAck) |
|
709 { |
|
710 printf("\n"); |
|
711 } |
|
712 |
|
713 // Else, send our acknowledgement packet to complete the transfer. |
|
714 else |
|
715 { |
|
716 seq = -1; |
|
717 TInt bytesUploaded = 0; |
|
718 r = SendPacket(seq, aStream, bytesUploaded); |
|
719 printf("\n"); |
|
720 if(r) |
|
721 { |
|
722 TraceLog("ERROR: SendImageFile r=%d (%s)", r, GetSymOrWinErrMsg(r)); |
|
723 } |
|
724 } |
|
725 } |
|
726 } |
|
727 |
|
728 // Else, print any error. |
|
729 else |
|
730 { |
|
731 printf("\n<SendPacket %d -> %d (%s)\n", seq, r, GetSymOrWinErrMsg(r)); |
|
732 TraceLog("ERROR: <SendPacket seq=%d r=%d (%s)", seq, r, GetSymOrWinErrMsg(r)); |
|
733 } |
|
734 |
|
735 return r; |
|
736 } |
|
737 |
|
738 void GetResponse() |
|
739 { |
|
740 TInt r; |
|
741 do { |
|
742 r = CommRead(LineBuf, MAX_LINE, 1000); |
|
743 if (r>=0) |
|
744 if(use_stdout) |
|
745 { |
|
746 LineBuf[r]=0; |
|
747 printf(LineBuf); |
|
748 } |
|
749 else |
|
750 { |
|
751 WriteLog(LineBuf, r); |
|
752 } |
|
753 } while (r>=0); |
|
754 } |
|
755 |
|
756 void IssueCommandAndGetResponse(const char* aCmd) |
|
757 { |
|
758 CommWriteS(aCmd); |
|
759 GetResponse(); |
|
760 } |
|
761 |
|
762 int token_length(const char* s) |
|
763 { |
|
764 const char* p = s; |
|
765 for (; *p && !isspace(*p); ++p) {} |
|
766 return p - s; |
|
767 } |
|
768 |
|
769 const char* skip_space(const char* s) |
|
770 { |
|
771 for (; *s && isspace(*s); ++s) {} |
|
772 return s; |
|
773 } |
|
774 |
|
775 TInt GetMonitorInfo() |
|
776 /* |
|
777 return 0 on success, -1 on failure |
|
778 */ |
|
779 { |
|
780 BOOL ok = FALSE; |
|
781 int l; |
|
782 int type; |
|
783 RESET_COMM(); |
|
784 IssueCommandAndGetResponse("replacement\xd"); |
|
785 IssueCommandAndGetResponse("f\xd"); |
|
786 const char* p = LineBuf; |
|
787 const char* q = LineBuf + strlen(LineBuf); |
|
788 while (p<q) |
|
789 { |
|
790 p = skip_space(p); |
|
791 if (p+16>q || memcmp(p, "Fault Category: ", 16)) |
|
792 { |
|
793 p += token_length(p); |
|
794 continue; |
|
795 } |
|
796 p = skip_space(p+16); |
|
797 l = token_length(p); |
|
798 if (l!=4 || memcmp(p, "KERN", 4)) |
|
799 { |
|
800 p += l; |
|
801 continue; |
|
802 } |
|
803 p = skip_space(p+4); |
|
804 if (p+14>q || memcmp(p, "Fault Reason: ", 14)) |
|
805 { |
|
806 p += token_length(p); |
|
807 continue; |
|
808 } |
|
809 p = skip_space(p+14); |
|
810 if (p+8<=q && memcmp(p, "00000050", 8)==0) |
|
811 { |
|
812 ok = true; |
|
813 break; |
|
814 } |
|
815 p+=8; |
|
816 continue; |
|
817 } |
|
818 if (ok) |
|
819 { |
|
820 // Add a line after the "." debug monitor prompt so the next log line won't appear next to it. |
|
821 TraceLog(""); |
|
822 |
|
823 return 0; |
|
824 } |
|
825 |
|
826 IssueCommandAndGetResponse("i\xd"); |
|
827 for (type=0; type<14; ++type) |
|
828 { |
|
829 char b[8]; |
|
830 sprintf(b, "c%x\xd", type); |
|
831 IssueCommandAndGetResponse(b); |
|
832 } |
|
833 |
|
834 IssueCommandAndGetResponse("S\xd"); |
|
835 |
|
836 // Optionally, dump the code segs to make it clear where non-XIP code is loaded |
|
837 // and make debugging easier. |
|
838 if(DebugMonitorOptions & kDebugDumpCodeSegs) |
|
839 { |
|
840 IssueCommandAndGetResponse("p all\xd"); |
|
841 } |
|
842 |
|
843 // Add a line after the "." debug monitor prompt so the next log line won't appear next to it. |
|
844 TraceLog(""); |
|
845 |
|
846 return -1; |
|
847 } |
|
848 |
|
849 TInt ReceiveTestLog(TInt aOverallTimeOutS) |
|
850 { |
|
851 TInt r=0; |
|
852 TInt r2; |
|
853 clock_t iterationStartTime = clock(); |
|
854 |
|
855 for(;;) |
|
856 { |
|
857 TBool checkDebugMonitor = false; |
|
858 |
|
859 r = CommRead(LineBuf, MAX_LINE, aOverallTimeOutS * 1000); |
|
860 |
|
861 // If a time-out occured, print an error message. |
|
862 if (r==KErrTimedOut) |
|
863 { |
|
864 clock_t elapsedTimeC = clock() - iterationStartTime; |
|
865 double elapsedTimeS = double(elapsedTimeC) / double(CLOCKS_PER_SEC); |
|
866 |
|
867 if(elapsedTimeS < 10.0) |
|
868 { |
|
869 if(!use_stdout) |
|
870 { |
|
871 fprintf(stderr, "Nothing received for past %.02f seconds\n", elapsedTimeS); |
|
872 } |
|
873 TraceLog("Nothing received for past %.02f seconds", elapsedTimeS); |
|
874 } |
|
875 else |
|
876 { |
|
877 elapsedTimeC /= CLOCKS_PER_SEC; |
|
878 clock_t elapsedM = max(elapsedTimeC / 60, 0L); |
|
879 clock_t elapsedS = max(elapsedTimeC % 60, 0L); |
|
880 |
|
881 if(!use_stdout) |
|
882 { |
|
883 fprintf(stderr, "Nothing received for past %02d:%02d minutes\n", elapsedM, elapsedS); |
|
884 } |
|
885 TraceLog("Nothing received for past %02d:%02d minutes", elapsedM, elapsedS); |
|
886 } |
|
887 |
|
888 checkDebugMonitor = true; |
|
889 } |
|
890 |
|
891 // If the string "Password: " was read, this probably indicates the kernel |
|
892 // has jumped into the debug monitor. |
|
893 if (r>=10 && memcmp(LineBuf+r-10, "Password: ", 10)==0) |
|
894 { |
|
895 checkDebugMonitor = true; |
|
896 } |
|
897 |
|
898 // If real data was received, print it to the selected output. |
|
899 if (r>0) |
|
900 { |
|
901 if (use_stdout) |
|
902 { |
|
903 LineBuf[r]=0; // terminate string |
|
904 printf(LineBuf); |
|
905 } |
|
906 else |
|
907 { |
|
908 WriteLog(LineBuf, r); |
|
909 } |
|
910 |
|
911 iterationStartTime = clock(); |
|
912 } |
|
913 |
|
914 // If an error occured, check to see if the debug monitor is running. If it is, |
|
915 // we can extract information about the fault and use it to reboot the board. |
|
916 if (checkDebugMonitor || (r==KErrTimedOut)) |
|
917 { |
|
918 // Send CR to see if it elicits monitor prompt. |
|
919 CommWriteC(0x0d); |
|
920 r2 = CommRead(LineBuf, 12, 1000); |
|
921 if (r2>0) |
|
922 { |
|
923 if(use_stdout) |
|
924 { |
|
925 LineBuf[r2]=0; |
|
926 printf(LineBuf); |
|
927 } |
|
928 else |
|
929 { |
|
930 WriteLog(LineBuf, r2); |
|
931 } |
|
932 } |
|
933 if (r2==12 && memcmp(LineBuf, "\xd\xaPassword: ", 12)==0) |
|
934 { |
|
935 break; |
|
936 } |
|
937 } |
|
938 |
|
939 // If an error occured and the debug monitor is not running, stop trying to receive the session log. |
|
940 if (r<0) |
|
941 { |
|
942 break; |
|
943 } |
|
944 } |
|
945 |
|
946 // Check to see if the debug monitor was successfully prompted. |
|
947 TT_ASSERT((r>0) || (r==KErrTimedOut)); |
|
948 if (r>0) |
|
949 { |
|
950 // The debug monitor is accessible so extract debugging information. |
|
951 r = GetMonitorInfo(); |
|
952 |
|
953 // Issue the command to try to reboot the board. |
|
954 CommWriteS("X\xd"); |
|
955 if (r) |
|
956 { |
|
957 r = KExitCodeFaulted; |
|
958 } |
|
959 else |
|
960 { |
|
961 r = KErrNone; |
|
962 } |
|
963 } |
|
964 else if(r<0) |
|
965 { |
|
966 // The board debug monitor is not accessible or the board has locked up. |
|
967 printf("Target hung\n"); |
|
968 TraceLog("Target hung"); |
|
969 r = KExitCodeHung; |
|
970 } |
|
971 |
|
972 return r; |
|
973 } |
|
974 |
|
975 TInt DetermineBaudRate(TInt aPort, TUint& outBaudRate, TBool& aOutStream) |
|
976 { |
|
977 TInt r = KErrNone; |
|
978 |
|
979 for( TUint i = 0; i < sizeof(KBaudRateSearchList) / sizeof(TUint); i ++ ) |
|
980 { |
|
981 // Set the COM port to use the next baud rate to try. |
|
982 if(i != 0) // hide the first test so that the UI for boards supporting 115200bps-only remains the same as it |
|
983 { // was before. |
|
984 printf("Testing COM%d at %dbps...", aPort, KBaudRateSearchList[i]); |
|
985 } |
|
986 TraceLog("Testing COM%d at %dbps", aPort, KBaudRateSearchList[i]); |
|
987 r = SetupCommPort(aPort, KBaudRateSearchList[i], true); |
|
988 |
|
989 if(r == KErrNone) |
|
990 { |
|
991 // Try to Y-modem handshake with the board. If we succeed then we have found the correct speed. |
|
992 r = Handshake(aOutStream, true); |
|
993 if(r == KErrNone) |
|
994 { |
|
995 if(i != 0) |
|
996 { |
|
997 // If we finished the first test (115200bps) successfully, we do not reveal the fact that we are |
|
998 // prepared to test multiple baud rates so that the UI for boards supporting 115200bps only remains |
|
999 // the same as it was before. |
|
1000 printf(" Succeeded\n", aPort, KBaudRateSearchList[i]); |
|
1001 } |
|
1002 TraceLog("Testing of COM%d at %dbps Succeeded", aPort, KBaudRateSearchList[i]); |
|
1003 outBaudRate = KBaudRateSearchList[i]; |
|
1004 |
|
1005 break; |
|
1006 } |
|
1007 else if(r == KExitCodeDOA) |
|
1008 { |
|
1009 // The board is stuck in the crash debugger and is unusable. |
|
1010 break; |
|
1011 } |
|
1012 else |
|
1013 { |
|
1014 if(i == 0) |
|
1015 { |
|
1016 // If we finished the first test (115200bps) unsuccessfully, at this point we reveal that we are |
|
1017 // testing multiple baud rates and report the results of the failure. |
|
1018 printf("Testing COM%d at %dbps...", aPort, KBaudRateSearchList[i]); |
|
1019 } |
|
1020 printf(" Failed (%d) %s\n", r, GetSymOrWinErrMsg(r)); |
|
1021 TraceLog("Testing of COM%d at %dbps Failed (%d) %s", aPort, KBaudRateSearchList[i], r, GetSymOrWinErrMsg(r)); |
|
1022 } |
|
1023 } |
|
1024 else if(r == KExitCodeUnsupportedBaudRate) |
|
1025 { |
|
1026 if(i == 0) |
|
1027 { |
|
1028 // If we finished the first test (115200bps) and the baud rate setting is unsupported, at this point |
|
1029 // we reveal that we are testing multiple baud rates and report the results of the failure. |
|
1030 printf("Testing COM%d at %dbps...", aPort, KBaudRateSearchList[i]); |
|
1031 } |
|
1032 printf(" COM%d port doesn't support this baud rate setting\n", aPort); |
|
1033 TraceLog("COM%d port doesn't support %dbps setting", aPort, KBaudRateSearchList[i]); |
|
1034 } |
|
1035 } |
|
1036 |
|
1037 return r; |
|
1038 } |
|
1039 |
|
1040 void UploadROM(TInt aPort, TUint& aInOutBaudRate) |
|
1041 { |
|
1042 // Open the ROM image file and copy it into memory. |
|
1043 FILE* img = fopen(ImgFileName, "rb"); |
|
1044 if (!img) |
|
1045 { |
|
1046 fprintf(stderr, "Can't open %s for read (%d) %s\n", ImgFileName, errno, strerror(errno)); |
|
1047 exit(KExitCodeImage); |
|
1048 } |
|
1049 fseek(img,0,SEEK_END); |
|
1050 ImgFileSize=ftell(img); |
|
1051 fseek(img,0,SEEK_SET); |
|
1052 TraceLog("ROM Image File Size = %d bytes\n", ImgFileSize); |
|
1053 ImgFileChunkBase = malloc(ImgFileSize); |
|
1054 TT_ASSERT(ImgFileChunkBase != NULL); |
|
1055 int n = fread(ImgFileChunkBase, 1, ImgFileSize, img); |
|
1056 TT_ASSERT(n == ImgFileSize); |
|
1057 fclose(img); |
|
1058 |
|
1059 // Check to see if we should flash the ROM image or the boot loader based |
|
1060 // on the filename of the tool. |
|
1061 if (strcmpi("flashimg", __argv[0])==0) |
|
1062 { |
|
1063 printf("Uploading image %s to flash ", ImgFileName); |
|
1064 if (strstr(ImgFileName, ".zip") || strstr(ImgFileName, ".zip")) |
|
1065 strcpy(ImgFileName, "flashimg.zip"); |
|
1066 else |
|
1067 strcpy(ImgFileName, "flashimg.bin"); |
|
1068 printf("[%s]\n", ImgFileName); |
|
1069 } |
|
1070 else if (strcmpi("flashldr", __argv[0])==0) |
|
1071 { |
|
1072 printf("Uploading image %s to flash as bootloader ", ImgFileName); |
|
1073 if (strstr(ImgFileName, ".zip") || strstr(ImgFileName, ".zip")) |
|
1074 strcpy(ImgFileName, "flashldr.zip"); |
|
1075 else |
|
1076 strcpy(ImgFileName, "flashldr.bin"); |
|
1077 printf("[%s]\n", ImgFileName); |
|
1078 } |
|
1079 |
|
1080 // Open the COM port. |
|
1081 OpenCommPort(aPort); |
|
1082 |
|
1083 // Check to see if we should try to automatically determine the baud rate. |
|
1084 TInt r; |
|
1085 TBool stream = true; |
|
1086 if(aInOutBaudRate == 0) |
|
1087 { |
|
1088 r = DetermineBaudRate(aPort, aInOutBaudRate, stream); |
|
1089 if(r != KErrNone) |
|
1090 { |
|
1091 if(r != KExitCodeDOA) // DetermineBaudRate prints its own error message for KExitCodeDOA |
|
1092 { |
|
1093 fprintf(stderr, "Unable to determine baud rate or the target is hung/unplugged\n"); |
|
1094 TraceLog("Unable to determine baud rate or the target is hung/unplugged"); |
|
1095 } |
|
1096 exit(r); |
|
1097 } |
|
1098 } |
|
1099 else |
|
1100 { |
|
1101 r = SetupCommPort(aPort, aInOutBaudRate); |
|
1102 if(r == KErrNone) |
|
1103 { |
|
1104 r = Handshake(stream); |
|
1105 } |
|
1106 if(r != KErrNone) |
|
1107 { |
|
1108 fprintf(stderr, "Unable to connect to target on COM%d at %dbps (%d) %s\n", aPort, aInOutBaudRate, r, GetSymOrWinErrMsg(r)); |
|
1109 TraceLog("Unable to connect to target on COM%d at %dbps (%d) %s", aPort, aInOutBaudRate, r, GetSymOrWinErrMsg(r)); |
|
1110 exit(r); |
|
1111 } |
|
1112 } |
|
1113 |
|
1114 // Send the image. |
|
1115 r = SendImageFile(aPort, aInOutBaudRate, stream); |
|
1116 |
|
1117 free(ImgFileChunkBase); |
|
1118 } |
|
1119 |
|
1120 TInt LogTargetOutput(const char* aLogFileName, TBool aUseStdOut, TInt aPort, TUint& aInOutBaudRate, TUint& aInOutLogBaudRate, TInt aOverallTimeOutS) |
|
1121 { |
|
1122 TInt r; |
|
1123 |
|
1124 // Switch to the session log baud rate (default 115200bps) - higher speeds are usually only used for serial |
|
1125 // upload and not for the log download. It is possible to utilise higher log baud rates by manually modifying |
|
1126 // the debugport code in the board support package. |
|
1127 if(aInOutBaudRate != aInOutLogBaudRate) |
|
1128 { |
|
1129 r = SetupCommPort(aPort, aInOutLogBaudRate); |
|
1130 |
|
1131 if(r != KErrNone) |
|
1132 { |
|
1133 fprintf(stderr, "Unable to switch to session log baud rate (%dbps) or the target is hung/unplugged\n", aInOutLogBaudRate); |
|
1134 TraceLog("Unable to switch to session log baud rate (%dbps) or the target is hung/unplugged", aInOutLogBaudRate); |
|
1135 exit(r); |
|
1136 } |
|
1137 |
|
1138 aInOutBaudRate = aInOutLogBaudRate; |
|
1139 } |
|
1140 |
|
1141 // Check to see if we are logging to STDOUT or to a file. |
|
1142 if(!aUseStdOut) |
|
1143 { |
|
1144 printf("Logging target output from COM%d at %dbps to %s...\n", aPort, aInOutLogBaudRate, aLogFileName); |
|
1145 TraceLog("BEGIN TARGET LOG", aLogFileName); |
|
1146 } |
|
1147 |
|
1148 // Receive the session log. |
|
1149 clock_t startTime = clock(); |
|
1150 r = ReceiveTestLog(aOverallTimeOutS); |
|
1151 |
|
1152 // Print the duration of the session. |
|
1153 clock_t elapsedTimeC = clock() - startTime; |
|
1154 double elapsedTimeS = double(elapsedTimeC) / double(CLOCKS_PER_SEC); |
|
1155 if(elapsedTimeS < 10.0) |
|
1156 { |
|
1157 if(!use_stdout) |
|
1158 { |
|
1159 printf("Target output log ended after %.02f seconds\n", elapsedTimeS); |
|
1160 } |
|
1161 TraceLog("END TARGET LOG after %.02f seconds", elapsedTimeS); |
|
1162 } |
|
1163 else |
|
1164 { |
|
1165 elapsedTimeC /= CLOCKS_PER_SEC; |
|
1166 clock_t elapsedM = max(elapsedTimeC / 60, 0L); |
|
1167 clock_t elapsedS = max(elapsedTimeC % 60, 0L); |
|
1168 |
|
1169 if(!use_stdout) |
|
1170 { |
|
1171 printf("Target output log ended after %02d:%02d minutes\n", elapsedM, elapsedS); |
|
1172 } |
|
1173 TraceLog("END TARGET LOG after %02d:%02d minutes", elapsedM, elapsedS); |
|
1174 } |
|
1175 |
|
1176 return r; |
|
1177 } |
|
1178 |
|
1179 void CloseSession() |
|
1180 { |
|
1181 // Perform cleanup... |
|
1182 |
|
1183 WriteLogS("\n\n"); |
|
1184 TraceLog("DONE"); |
|
1185 |
|
1186 EscapeCommFunction(Comm, CLRRTS); |
|
1187 EscapeCommFunction(Comm, CLRDTR); |
|
1188 |
|
1189 if(Comm != INVALID_HANDLE_VALUE) |
|
1190 { |
|
1191 CloseHandle(Comm); |
|
1192 Comm = INVALID_HANDLE_VALUE; |
|
1193 } |
|
1194 |
|
1195 if (LogFile) |
|
1196 { |
|
1197 fclose(LogFile); |
|
1198 LogFile = NULL; |
|
1199 } |
|
1200 } |
|
1201 |
|
1202 void PrintHelp() |
|
1203 { |
|
1204 fprintf(stderr, "\n"); |
|
1205 fprintf(stderr, "TrgTest Serial Y-Modem Upload Test Utility\n"); |
|
1206 fprintf(stderr, "==========================================\n\n"); |
|
1207 fprintf(stderr, "trgtest port# [-b<baudrate> default: 0 (auto)] [-lb<baudrate> default: 115200]"); |
|
1208 fprintf(stderr, " imagefilename [logfilename] [timeout]\n\n"); |
|
1209 fprintf(stderr, " port# = COM port e.g., \"1\"\n"); |
|
1210 fprintf(stderr, " -b (optional) = ROM image serial upload baud rate e.g., \"-b115200\"\n"); |
|
1211 fprintf(stderr, " -lb (opt.) = session log download baud rate e.g., \"-lb115200\"\n"); |
|
1212 fprintf(stderr, " imagefilename = path to ROM image e.g., \"rom.img\" or \"nul\" for no image\n"); |
|
1213 fprintf(stderr, " logfilename (opt.) = path to session log e.g., \"test.log\" or \"-\" for STDOUT\n"); |
|
1214 fprintf(stderr, " timeout (opt.) = timeout after inactivity in seconds e.g., \"1800\"\n\n"); |
|
1215 fprintf(stderr, "Example Usage:\n\n"); |
|
1216 fprintf(stderr, " trgtest 1 rom.img log.txt\n"); |
|
1217 } |
|
1218 |
|
1219 |
|
1220 int main(int argc, char** argv) |
|
1221 { |
|
1222 TInt r = KErrNone; |
|
1223 TInt port = 0; |
|
1224 TUint baudRate = 0; |
|
1225 TUint logBaudRate = 0; |
|
1226 TInt overallTimeOutS = 1800; // default time to wait for output (in seconds) |
|
1227 const char* logfilename = NULL; |
|
1228 int paramIndex = 1; |
|
1229 |
|
1230 // Disable stream buffering. |
|
1231 setvbuf(stdout,NULL,_IONBF,0); |
|
1232 |
|
1233 // Print help if the parameter count is incorrect. |
|
1234 if (argc<3 || argc>7) |
|
1235 { |
|
1236 PrintHelp(); |
|
1237 exit(KExitCodeUsage); |
|
1238 } |
|
1239 |
|
1240 // Get the COM port. |
|
1241 if(isdigit(argv[paramIndex][0])) |
|
1242 { |
|
1243 port = atoi(argv[paramIndex]); |
|
1244 if(port == 0) |
|
1245 { |
|
1246 fprintf(stderr, "\"0\" is not valid - specify a serial COM port index number >= 1"); |
|
1247 exit(KExitCodeUsage); |
|
1248 } |
|
1249 paramIndex ++; |
|
1250 } |
|
1251 else |
|
1252 { |
|
1253 fprintf(stderr, "\"%s\" is not valid - specify a serial COM port index number >= 1", argv[paramIndex]); |
|
1254 exit(KExitCodeUsage); |
|
1255 } |
|
1256 |
|
1257 // Parse the optional parameters - order is not important. |
|
1258 while(paramIndex < argc) |
|
1259 { |
|
1260 // Get the serial upload baud rate. |
|
1261 if(StrCmpNI(argv[paramIndex], "-b", 2) == 0) |
|
1262 { |
|
1263 baudRate = atoi(argv[paramIndex] + 2); |
|
1264 paramIndex ++; |
|
1265 } |
|
1266 |
|
1267 // Get the session log baud rate. |
|
1268 else if(StrCmpNI(argv[paramIndex], "-lb", 3) == 0) |
|
1269 { |
|
1270 logBaudRate = atoi(argv[paramIndex] + 3); |
|
1271 paramIndex ++; |
|
1272 } |
|
1273 |
|
1274 // Stop if we parse an unknown option - it is probably the ROM image file path. |
|
1275 else |
|
1276 { |
|
1277 break; |
|
1278 } |
|
1279 } |
|
1280 |
|
1281 // If no session log baud rate was specified, set the default rate of 115200bps. |
|
1282 if(logBaudRate == 0) |
|
1283 { |
|
1284 logBaudRate = KDefaultBaudRate; |
|
1285 } |
|
1286 |
|
1287 // Get the ROM image file path. |
|
1288 if(paramIndex >= argc) |
|
1289 { |
|
1290 fprintf(stderr, "No ROM image file specified\n"); |
|
1291 exit(KExitCodeUsage); |
|
1292 } |
|
1293 strcpy(ImgFileName, argv[paramIndex]); |
|
1294 paramIndex ++; |
|
1295 |
|
1296 // Get the session log options. |
|
1297 if (paramIndex < argc) |
|
1298 { |
|
1299 // Check to see if TrgTest should log the target output and to what. |
|
1300 logfilename = argv[paramIndex]; |
|
1301 if (!strcmp(logfilename, "-")) |
|
1302 { |
|
1303 printf("After the upload has completed, TrgTest will read from the serial port and write to STDOUT.\n"); |
|
1304 use_stdout = true; |
|
1305 } |
|
1306 else |
|
1307 { |
|
1308 LogFile = fopen(logfilename, "wb"); |
|
1309 |
|
1310 if (!LogFile) |
|
1311 { |
|
1312 fprintf(stderr, "Can't open %s for write (%d) %s\n", logfilename, errno, strerror(errno)); |
|
1313 exit(KExitCodeLog); |
|
1314 } |
|
1315 |
|
1316 // Disable stream buffering. |
|
1317 setvbuf(LogFile,NULL,_IONBF,0); |
|
1318 } |
|
1319 paramIndex ++; |
|
1320 |
|
1321 // Check to see if a non-default inactivity timeout has been specified. |
|
1322 if (paramIndex < argc) |
|
1323 { |
|
1324 overallTimeOutS = atoi(argv[paramIndex]); |
|
1325 } |
|
1326 } |
|
1327 |
|
1328 TBool sendImage = strcmpi(ImgFileName, "nul") != 0; |
|
1329 |
|
1330 // Log the trgtest parameters. |
|
1331 TraceLog("Port = COM%d", port); |
|
1332 if(sendImage) |
|
1333 { |
|
1334 if(baudRate == 0) |
|
1335 { |
|
1336 TraceLog("Baud Rate = Auto"); |
|
1337 } |
|
1338 else |
|
1339 { |
|
1340 TraceLog("Baud Rate = %dbps", baudRate); |
|
1341 } |
|
1342 TraceLog("ROM Image = %s", ImgFileName); |
|
1343 } |
|
1344 else |
|
1345 { |
|
1346 TraceLog("ROM Image = None"); |
|
1347 } |
|
1348 TraceLog("Log Baud Rate = %dbps", logBaudRate); |
|
1349 if(use_stdout) |
|
1350 { |
|
1351 TraceLog("Log = STDOUT"); |
|
1352 } |
|
1353 else if(logfilename) |
|
1354 { |
|
1355 TraceLog("Log = %s", logfilename); |
|
1356 } |
|
1357 else |
|
1358 { |
|
1359 TraceLog("Log = None", logfilename); |
|
1360 } |
|
1361 TraceLog("Inactivity Timeout = %d secs.", overallTimeOutS); |
|
1362 if(DebugMonitorOptions & kDebugDumpCodeSegs) |
|
1363 { |
|
1364 TraceLog("Debug Monitor Options = Dump Code Segs"); |
|
1365 } |
|
1366 else |
|
1367 { |
|
1368 TraceLog("Debug Monitor Options = None"); |
|
1369 } |
|
1370 |
|
1371 // Initiate serial upload if a ROM image was specified. |
|
1372 if(sendImage) |
|
1373 { |
|
1374 UploadROM(port, baudRate); |
|
1375 } |
|
1376 |
|
1377 if(r==KErrNone) |
|
1378 { |
|
1379 // Check to see if the ROM upload (if any) succeeded. |
|
1380 if(sendImage) |
|
1381 { |
|
1382 printf("Sent image file OK\n"); |
|
1383 TraceLog("Sent image file OK"); |
|
1384 } |
|
1385 |
|
1386 // Check to see if we should log the target output. |
|
1387 if (LogFile || use_stdout) |
|
1388 { |
|
1389 // If no serial upload was performed the COM port is not yet open. |
|
1390 if(!sendImage) |
|
1391 { |
|
1392 // Open the COM port. |
|
1393 OpenCommPort(port); |
|
1394 } |
|
1395 |
|
1396 // Log the target output if a log file was specified. |
|
1397 r = LogTargetOutput(logfilename, use_stdout, port, baudRate, logBaudRate, overallTimeOutS); |
|
1398 } |
|
1399 } |
|
1400 else |
|
1401 { |
|
1402 printf("SendImageFile upload failed -> (%d) %s\n", r, GetSymOrWinErrMsg(r)); |
|
1403 TraceLog("SendImageFile upload failed -> (%d) %s", r, GetSymOrWinErrMsg(r)); |
|
1404 r = KExitCodeDownload; |
|
1405 } |
|
1406 |
|
1407 // Close the session |
|
1408 CloseSession(); |
|
1409 |
|
1410 // Print any exit error. |
|
1411 if (r!=KErrNone) |
|
1412 { |
|
1413 fprintf(stderr, "Exiting with error %d\n", r); |
|
1414 } |
|
1415 |
|
1416 return r; |
|
1417 } |