comparison host/tools/ecostest/common/ResetAttributes.cpp @ 76:435cced73e2f ecos-v1_3_1-release

eCos v1.3.1 merged from eCos master repository on 2000-03-27-23:22:51-BST
author jlarmour
date Tue, 28 Mar 2000 14:10:45 +0000
parents
children 6736c52df507
comparison
equal deleted inserted replaced
75:41bf073c0c32 76:435cced73e2f
1 //####COPYRIGHTBEGIN####
2 //
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
5 //
6 // This program is part of the eCos host tools.
7 //
8 // This program is free software; you can redistribute it and/or modify it
9 // under the terms of the GNU General Public License as published by the Free
10 // Software Foundation; either version 2 of the License, or (at your option)
11 // any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but WITHOUT
14 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 // more details.
17 //
18 // You should have received a copy of the GNU General Public License along with
19 // this program; if not, write to the Free Software Foundation, Inc.,
20 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 //
22 // ----------------------------------------------------------------------------
23 //
24 //####COPYRIGHTEND####
25 //#####DESCRIPTIONBEGIN####
26 //
27 // Author(s): sdf
28 // Contributors: sdf
29 // Date: 1999-04-01
30 // Description: Holds information related to target reset
31 // Usage:
32 //
33 //####DESCRIPTIONEND####
34 #include "eCosStd.h"
35 #include "eCosThreadUtils.h"
36 #include "eCosTrace.h"
37 #include "ResetAttributes.h"
38
39 const CResetAttributes CResetAttributes::NoReset;
40
41 LPCTSTR CResetAttributes::Image(int nErr)
42 {
43 switch(nErr){
44 case RESET_OK:
45 return _T("RESET_OK");
46 break;
47 case RESET_ILLEGAL_DEVICE_CODE:
48 return _T("Illegal device code");
49 break;
50 case RESET_NO_REPLY:
51 return _T("No reply from reset unit");
52 break;
53 case RESET_BAD_CHECKSUM:
54 return _T("Bad checksum");
55 break;
56 case RESET_BAD_ACK:
57 return _T("Bad ack");
58 break;
59 default:
60 return _T("Unknown reset error");
61 break;
62 }
63 }
64
65 void CResetAttributes::SuckThreadFunc()
66 {
67 m_strResetOutput.SetLength(0);
68
69 // Board has apparently been powered on. Suck initial output.
70 String strMsg;
71 strMsg.Format(_T(">>> Reading board startup output from %s with timeout of %d seconds...\n"),(LPCTSTR)m_strAuxPort,m_nReadTimeout/1000);
72 ResetLog(strMsg);
73
74 enum {BUFSIZE=512};
75 TCHAR *buf=new TCHAR[BUFSIZE];
76 memset(buf,0,BUFSIZE); // safety for string functions in IsValidReset
77 TCHAR *c=buf;
78 do {
79 unsigned int dwRead=0;
80 // We are working in non-blocking mode
81 if(m_Socket.Ok()){
82 if(!m_Socket.Peek(dwRead)||!m_Socket.recv(c,MIN(dwRead,(unsigned)BUFSIZE-(c-buf)))){
83 break;
84 }
85 } else if (!m_Serial.Read(c,BUFSIZE-(c-buf),dwRead)){
86 m_Serial.ClearError();
87 c=buf;
88 }
89 if(dwRead>0){
90 c[dwRead]=_TCHAR('\0');
91 {
92 String str;
93 for(const TCHAR *t=c;*t;t++){
94 if(_istprint(*t)){
95 str+=*t;
96 }
97 }
98 ResetLog(str);
99 }
100
101 for(int i=dwRead-1;i>=0;--i){
102 if(c[i]<0x20 || c[i]>=0x7f){
103 // Control character - assume nothing up to this is of interest
104 i++;
105 dwRead-=i;
106 memmove(c,c+i,dwRead);
107 break;
108 }
109 }
110 c+=dwRead;
111 if(IsValidReset((void *)buf)){
112 ResetLog(_T("\n>>> Valid reset determined\n"));
113 break;
114 }
115 } else { // Nothing read
116 Sleep(500);
117 }
118 } while (0==m_tResetOccurred || Now()-m_tResetOccurred<m_nReadTimeout);
119 m_strResetOutput=buf;
120 delete [] buf;
121 if(0==m_strResetOutput.GetLength()){
122 ResetLog(_T("\n>>> No response from board\n"));
123 }
124 }
125
126 bool CResetAttributes::Reset(Action action,bool bCheckOutput)
127 {
128 m_strResetOutput=_T("");
129 bool rc=false;
130 CeCosTestSocket sock;
131 time_t ltime;
132 time(&ltime);
133 struct tm *now=localtime( &ltime );
134 String strStatus;
135
136 if(bCheckOutput){
137 strStatus.Format(_T(">>> Reset target using %s %s port=%s(%d) read timeout=%d delay=%d [%02d:%02d:%02d]\n"),
138 (LPCTSTR)m_strHostPort,(LPCTSTR)m_strControl, (LPCTSTR)m_strAuxPort, m_nBaud, m_nReadTimeout, m_nDelay,
139 now->tm_hour,now->tm_min,now->tm_sec);
140 } else {
141 strStatus.Format(_T(">>> Reset target using %s %s delay=%d [%02d:%02d:%02d]\n"),
142 (LPCTSTR)m_strHostPort,(LPCTSTR)m_strControl, m_nDelay,
143 now->tm_hour,now->tm_min,now->tm_sec);
144 }
145 ResetLog(strStatus);
146
147 // Open up communication to port whence we read the board startup
148 bool bThreadDone=false;
149 bCheckOutput&=(m_strAuxPort.GetLength()>0);
150 if(bCheckOutput){
151 TRACE(_T("Opening %s\n"),(LPCTSTR)m_strAuxPort);
152 String strHost;
153 int nPort;
154 if(CeCosTestSocket::ParseHostPort(m_strAuxPort,strHost,nPort)){
155 // tcp/ip port
156 if(!m_Socket.Connect(strHost,nPort,m_nReadTimeout)){
157 String str;
158 str.Format(_T("Failed to open %s - %s\n"),(LPCTSTR)m_strAuxPort,(LPCTSTR)m_Socket.SocketErrString());
159 ResetLog(str);
160 return false;
161 }
162 } else {
163 // Comms device
164 m_Serial.SetBlockingReads(false);
165 if(m_Serial.Open(m_strAuxPort,m_nBaud)){
166 m_Serial.Flush();
167 } else {
168 String str;
169 str.Format(_T("Failed to open comms port %s - %s\n"),(LPCTSTR)m_strAuxPort,(LPCTSTR)m_Serial.ErrString());
170 ResetLog(str);
171 return false;
172 }
173 }
174 CeCosThreadUtils::RunThread(SSuckThreadFunc,this,&bThreadDone,_T("SSuckThreadFunc"));
175 } else {
176 ResetLog(_T(">>> [not checking output]\n"));
177 }
178
179 String strHost;
180 int nPort;
181 // This will be true if we need to talk to a reset server, false to talk down a local port
182 bool bRemote=CeCosTestSocket::ParseHostPort(m_strHostPort,strHost,nPort);
183 if(bRemote){
184 if(sock.Connect(strHost,nPort,10*1000)){
185 m_tResetOccurred=0;
186 // Write the message to the socket
187 String strCmd;
188 int nDelay=(action==ON_OFF || action==OFF_ON)?m_nDelay:0;
189 strCmd.Format(_T("-Control=%s -Action=%d -Delay=%d"),(LPCTSTR)m_strControl,action,nDelay);
190 TRACE(_T("-Control=%s -Action=%d -Delay=%d"),(LPCTSTR)m_strControl,action,0);
191 if(sock.sendString(strCmd,_T("Reset control codes"), 10*1000)){
192 // Wait for an acknowledgement
193 String strResponse;
194 if(sock.recvString(strResponse, _T("Response"), 20*1000)){
195 rc=(0==strResponse.GetLength());
196 if(!rc && m_pfnReset){
197 String strMsg;
198 strMsg.Format(_T("Reset server reports error '%s'\n"),(LPCTSTR)strResponse);
199 ResetLog(strMsg);
200 }
201 } else {
202 String str;
203 str.Format(_T(">>> Failed to read response from reset server %s - %s\n"),(LPCTSTR)m_strHostPort,(LPCTSTR)sock.SocketErrString());
204 ResetLog(str);
205 }
206 } else {
207 String str;
208 str.Format(_T(">>> Failed to contact reset server %s - %s\n"),(LPCTSTR)m_strHostPort,(LPCTSTR)sock.SocketErrString());
209 ResetLog(str);
210 ResetLog(_T(">>> Failed to contact reset server\n"));
211 }
212 m_tResetOccurred=Now();
213 if(bCheckOutput){
214 if(!rc){
215 // force thread to time out
216 m_tResetOccurred=Now()-m_nReadTimeout;
217 }
218 CeCosThreadUtils::WaitFor(bThreadDone); // do not apply a timeout - the thread has one
219 rc=IsValidReset((void *)(LPCTSTR)m_strResetOutput);
220 ResetLog(rc?_T(">>> Reset output valid\n"):_T("!!! Reset output invalid\n"));
221 }
222 } else {
223 String str;
224 str.Format(_T(">>> Failed to contact reset server %s - %s\n"),(LPCTSTR)m_strHostPort,(LPCTSTR)sock.SocketErrString());
225 ResetLog(str);
226 ResetLog(_T(">>> Failed to contact reset server\n"));
227 }
228 } else {
229 // Sending something locally
230 m_tResetOccurred=Now();
231 unsigned int nWritten;
232 m_Serial.Write((void *)(LPCTSTR)m_strControl,1,nWritten);
233 if(bCheckOutput){
234 CeCosThreadUtils::WaitFor(bThreadDone); // do not apply a timeout - the thread has one
235 rc=IsValidReset((void *)(LPCTSTR)m_strResetOutput);
236 ResetLog(rc?_T(">>> Reset output valid\n"):_T("!!! Reset output invalid\n"));
237 }
238 }
239
240 if(m_Socket.Ok()){
241 m_Socket.Close();
242 } else {
243 m_Serial.Close();
244 }
245 return rc && bCheckOutput;
246 }
247
248 const TCHAR *CResetAttributes::GetIdAndArg (LPCTSTR psz,String &strID,String &strArg)
249 {
250 const TCHAR *cEnd=_tcschr(psz,_TCHAR('('));
251 if(cEnd){
252 strID=String(psz,cEnd-psz);
253 int nNest=0;
254 for(const TCHAR *c=cEnd;*c;c++){
255 if(_TCHAR('(')==*c){
256 nNest++;
257 } else if(_TCHAR(')')==*c){
258 nNest--;
259 if(0==nNest){
260 strArg=String(cEnd+1,c-(cEnd+1));
261 return c+1;
262 }
263 }
264 }
265 assert(false);
266 }
267 return 0;
268 }
269
270 int CResetAttributes::GetArgs(LPCTSTR psz,StringArray &ar)
271 {
272 ar.clear();
273 if(0==*psz){
274 return 0;
275 } else {
276 String str;
277 for(const TCHAR *c=psz;*c;c++){
278 if(_TCHAR(',')==*c){
279 ar.push_back(str);
280 str=_T("");
281 } else {
282 str+=*c;
283 }
284 }
285 ar.push_back(str);
286 return ar.size();
287 }
288 }
289
290 // m_str will hold something like
291 // 3(off(ginga:5000,a1) delay(2000) on(,..com2,38400))
292 CResetAttributes::ResetResult CResetAttributes::Reset (LogFunc *pfnLog, void *pfnLogparam,bool bCheckOnly)
293 {
294 m_pfnReset=pfnLog;
295 m_pfnResetparam=pfnLogparam;
296
297 const TCHAR *c;
298 String str;
299 // Remove spaces
300 for(c=m_str;*c;c++){
301 if(!_istspace(*c)){
302 str+=*c;
303 }
304 }
305
306 // Check paren matching:
307 int nNest=0;
308 for(c=str;*c;c++){
309 if(_TCHAR('(')==*c){
310 nNest++;
311 } else if(_TCHAR(')')==*c){
312 nNest--;
313 if(nNest<0){
314 ResetLog(_T("Too many right parentheses"));
315 return INVALID_STRING;
316 }
317 }
318 }
319 if(nNest>0){
320 ResetLog(_T("Too many left parentheses"));
321 return INVALID_STRING;
322 }
323
324 m_nReadTimeout=10*1000;
325 m_nBaud=38400;
326 m_nDelay=1000;
327
328 return Parse(str,bCheckOnly);
329 }
330
331 // 3(off(ginga:5000,a1) delay(2000) on(,..com2,38400))
332 CResetAttributes::ResetResult CResetAttributes::Parse (LPCTSTR psz,bool bCheckOnly)
333 {
334 bool bCheck=false;
335 for(const TCHAR *c=psz;*c;){
336 String strID,strArg;
337 c=GetIdAndArg(c,strID,strArg);
338 if(0==c){
339 ResetLog(_T("Invalid reset string"));
340 return INVALID_STRING;
341 }
342
343 if(isdigit(*(LPCTSTR)strID)){
344 int nRepeat=_ttoi(strID);
345 if(0==nRepeat){
346 ResetLog(_T("Invalid reset string"));
347 return INVALID_STRING;
348 }
349 if(bCheckOnly){
350 return Parse(strArg,true);
351 } else {
352 while(nRepeat--){
353 ResetResult r=Parse(strArg);
354 if(RESET_OK==r||INVALID_STRING==r){
355 return r;
356 }
357 }
358 }
359 } else if (_T("port")==strID) {
360 // 0. Port
361 // 1. Baud
362 // 2. Timeout
363 StringArray ar;
364 int nArgs=GetArgs(strArg,ar);
365 if(nArgs>0 && ar[0].GetLength()){
366 m_strAuxPort=ar[0];
367 }
368 if(nArgs>1 && ar[1].GetLength()){
369 m_nBaud=_ttoi(ar[1]);
370 }
371 if(nArgs>2 && ar[2].GetLength()){
372 m_nReadTimeout=_ttoi(ar[2]);
373 }
374 } else if (_T("off")==strID || _T("on")==strID || _T("on_off")==strID || _T("off_on")==strID) {
375 // args are:
376 // 0. Reset host:port
377 // 1. Control string
378 // 2. Port
379 // 3. Baud
380 // 4. Read timeout
381 // 5. Delay
382 StringArray ar;
383 int nArgs=GetArgs(strArg,ar);
384 if(nArgs>0 && ar[0].GetLength()){
385 m_strHostPort=ar[0];
386 }
387 if(nArgs>1 && ar[1].GetLength()){
388 m_strControl=ar[1];
389 }
390 if(nArgs>2 && ar[2].GetLength()){
391 m_strAuxPort=ar[2];
392 }
393 if(nArgs>3 && ar[3].GetLength()){
394 m_nBaud=_ttoi(ar[3]);
395 }
396 if(nArgs>4 && ar[4].GetLength()){
397 m_nReadTimeout=_ttoi(ar[4]);
398 }
399 if(nArgs>5 && ar[5].GetLength()){
400 m_nDelay=_ttoi(ar[5]);
401 }
402
403 if(0==m_strHostPort.GetLength()){
404 ResetLog(_T("Failed to specify reset host:port"));
405 return INVALID_STRING;
406 }
407
408 Action action=ON; // prevent compiler warning
409 if(_T("on")==strID){
410 action=ON;
411 } else if(_T("off")==strID){
412 action=OFF;
413 } else if(_T("on_off")==strID){
414 action=ON_OFF;
415 } else if(_T("off_on")==strID){
416 action=OFF_ON;
417 }
418
419 if(!bCheckOnly && Reset(action,bCheck||action==ON_OFF||action==OFF_ON)){
420 return RESET_OK;
421 }
422 bCheck ^= 1;
423 } else if (_T("delay")==strID) {
424 TRACE(_T("Sleep %d\n"),_ttoi(strArg));
425 if(!bCheckOnly){
426 Sleep(_ttoi(strArg));
427 }
428 } else {
429 ResetLog(_T("Unrecognized command"));
430 return INVALID_STRING;
431 }
432 }
433 ResetLog(_T("!!! Target reset not verified\n"));
434 return NOT_RESET;
435 }
436
437 void CResetAttributes::ResetLog(LPCTSTR psz)
438 {
439 if(m_pfnReset){
440 ENTERCRITICAL;
441 m_pfnReset(m_pfnResetparam,psz);
442 TRACE(_T("%s"),psz);
443 LEAVECRITICAL;
444 }
445 }
446
447 // This function determines whether the board startup has all that is required
448 // It is a hack because it has hardwired knowledge of what boards say at startup time
449 bool CALLBACK CResetAttributes::IsValidReset (void *pParam)
450 {
451 bool rc=false;
452 LPCTSTR pszBuf=(LPCTSTR)pParam;
453
454 // Look for $T or $S
455 LPCTSTR pcTpkt=_tcsstr(pszBuf,_T("$T"));
456 if(0==pcTpkt){
457 pcTpkt=_tcsstr(pszBuf,_T("$S"));
458 }
459
460 if(pcTpkt){
461 // T packet ends with #hh
462 LPCTSTR d=_tcschr(pcTpkt,_TCHAR('#'));
463 if(d && d[1] && d[2]){
464 rc=true;
465 }
466 } else if (_tcsstr(pszBuf,_T("cygmon> "))) {
467 rc=true;
468 } else {
469 LPCTSTR pBootp=_tcsstr(pszBuf,_T("BOOTP got "));
470 if(pBootp){
471 int i1,i2,i3,i4;
472 rc=(4==_stscanf(pBootp+10,_T("%d.%d.%d.%d"),&i1,&i2,&i3,&i4));
473 }
474 }
475 return rc;
476 }
477
478 bool CResetAttributes::IsValid()
479 {
480 return INVALID_STRING!=Reset (0,0,true);
481 }