Mercurial > flash_v2
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(<ime); | |
| 133 struct tm *now=localtime( <ime ); | |
| 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 } |
