0
|
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 |
}
|