source: SVN/cambria/redboot/host/tools/ecostest/common/ResetAttributes.cpp @ 1

Last change on this file since 1 was 1, checked in by Tim Harvey, 2 years ago

restored latest version of files from server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 12.9 KB
Line 
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
39const CResetAttributes CResetAttributes::NoReset;
40
41CResetAttributes::CResetAttributes(LPCTSTR psz) : 
42  // Default values:
43  m_nDelay(1000),
44  m_nReadTimeout(10*1000),
45  m_nBaud(38400)
46{
47  // Remove spaces
48  while(*psz){
49    if(!_istspace(*psz)){
50      m_str+=*psz;
51    }
52    psz++;
53  }
54}
55
56/*
57LPCTSTR CResetAttributes::Image(int nErr)
58{
59  switch(nErr){
60    case RESET_OK:
61      return _T("RESET_OK");
62      break;
63    case RESET_ILLEGAL_DEVICE_CODE:
64      return _T("Illegal device code");
65      break;
66    case RESET_NO_REPLY:
67      return _T("No reply from reset unit");
68      break;
69    case RESET_BAD_CHECKSUM:
70      return _T("Bad checksum");
71      break;
72    case RESET_BAD_ACK:
73      return _T("Bad ack");
74      break;
75    default:
76      return _T("Unknown reset error");
77      break;
78  }
79}
80*/
81void CResetAttributes::SuckThreadFunc()
82{
83  m_strResetOutput=_T("");
84 
85  // Board has apparently been powered on.  Suck initial output.
86  ResetLog(String::SFormat(_T("Reading board startup output from %s with timeout of %d seconds..."),(LPCTSTR)m_strAuxPort,m_nReadTimeout/1000));
87
88  enum {BUFSIZE=512};
89  TCHAR buf[1+BUFSIZE];
90  memset(buf,0,BUFSIZE); // safety for string functions in IsValidReset
91  do {
92    unsigned int dwRead=0;
93    // We are working in non-blocking mode
94    if(m_Socket.Ok()){
95      if(!m_Socket.Peek(dwRead)||!m_Socket.recv(buf,MIN(dwRead,BUFSIZE))){
96        break;
97      }
98    } else if (!m_Serial.Read(buf,BUFSIZE,dwRead)){
99      m_Serial.ClearError();
100      continue;
101    } 
102    if(dwRead>0){
103      buf[dwRead]=_TCHAR('\0');
104     
105      // Remove unprintable characters
106      String str;
107      for(const TCHAR *t=buf;*t;t++){
108        if(_istprint(*t)){
109          str+=*t;
110        }
111      }
112
113      if(m_pfnReset){
114        ENTERCRITICAL;
115        m_pfnReset(m_pfnResetparam,str);
116        LEAVECRITICAL;
117      }
118
119      ResetLog(str);
120      m_strResetOutput+=str;
121
122      if(IsValidReset()){
123        break;
124      }
125//    } else { // Nothing read
126//      CeCosThreadUtils::Sleep(50);
127    }
128  } while (0==m_tResetOccurred || Now()-m_tResetOccurred<m_nReadTimeout);
129
130  if(0==m_strResetOutput.size()){
131    ResetLog(_T("No response from board"));
132  } else {
133    if(m_pfnReset){
134      ENTERCRITICAL;
135      m_pfnReset(m_pfnResetparam,_T("\n"));
136      LEAVECRITICAL;
137    }
138    TRACE(_T("%s"),(LPCTSTR)m_strResetOutput);
139  }
140}
141
142bool CResetAttributes::Reset(Action action,bool bCheckOutput)
143{
144  m_tResetOccurred=0;
145  m_strResetOutput=_T("");
146  bool rc=false;
147  CeCosSocket sock;
148  String strStatus;
149  strStatus.Format(_T("Reset target using %s %s port=%s(%d) read timeout=%d delay=%d"),
150    (LPCTSTR)m_strHostPort,(LPCTSTR)m_strControl, 
151    (LPCTSTR)m_strAuxPort, m_nBaud, m_nReadTimeout, m_nDelay);
152  if(bCheckOutput){
153    strStatus+=_T(" expect(");
154    for(unsigned int i=0;i<m_arValidResetStrings.size();i++){
155      if(i>0){
156        strStatus+=_TCHAR(',');
157      }
158      strStatus+=m_arValidResetStrings[i];
159    }
160    strStatus+=_T(")");
161  }
162  ResetLog(strStatus);
163
164  // Open up communication to port whence we read the board startup
165  bool bThreadDone=false;
166  bCheckOutput&=(m_strAuxPort.size()>0);
167  if(bCheckOutput){
168    TRACE(_T("Opening %s\n"),(LPCTSTR)m_strAuxPort);
169    if(CeCosSocket::IsLegalHostPort(m_strAuxPort)){
170      // tcp/ip port
171      if(!m_Socket.Connect(m_strAuxPort,m_nReadTimeout)){
172        ResetLog(String::SFormat(_T("Failed to open %s - %s"),(LPCTSTR)m_strAuxPort,(LPCTSTR)m_Socket.SocketErrString()));
173        return false;
174      }
175    } else {
176      // Comms device
177      m_Serial.SetBlockingReads(false);
178      if(m_Serial.Open(m_strAuxPort,m_nBaud)){
179        m_Serial.Flush();
180      } else {
181        ResetLog(String::SFormat(_T("Failed to open comms port %s - %s"),(LPCTSTR)m_strAuxPort,(LPCTSTR)m_Serial.ErrString()));
182        return false;
183      }
184    }
185    CeCosThreadUtils::RunThread(SSuckThreadFunc,this,&bThreadDone,_T("SSuckThreadFunc"));
186  } else {
187    ResetLog(_T("[not checking output]"));
188  }
189 
190  // This will be true if we need to talk to a reset server, false to talk down a local port
191  bool bRemote=CeCosSocket::IsLegalHostPort(m_strHostPort);
192  if(bRemote){
193    if(sock.Connect(m_strHostPort,10*1000)){
194      // Write the message to the socket
195      int nDelay=(action==ON_OFF || action==OFF_ON)?m_nDelay:0;
196      TRACE(_T("-Control=%s -Action=%d -Delay=%d"),(LPCTSTR)m_strControl,action,nDelay);
197      if(sock.sendString(String::SFormat(_T("-Control=%s -Action=%d -Delay=%d"),(LPCTSTR)m_strControl,action,nDelay),_T("Reset control codes"), 10*1000)){
198        // Wait for an acknowledgement
199        String strResponse;
200        if(sock.recvString(strResponse, _T("Response"), nDelay+20*1000)){
201          rc=(0==strResponse.size());
202          if(!rc && m_pfnReset){
203            ResetLog(String::SFormat(_T("Reset server reports error '%s'"),(LPCTSTR)strResponse));
204          }
205        } else {
206          ResetLog(String::SFormat(_T("Failed to read response from reset server %s - %s"),(LPCTSTR)m_strHostPort,(LPCTSTR)sock.SocketErrString()));
207        }
208      } else {
209        ResetLog(String::SFormat(_T("Failed to contact reset server %s - %s"),(LPCTSTR)m_strHostPort,(LPCTSTR)sock.SocketErrString()));
210      }
211      m_tResetOccurred=Now();
212      if(bCheckOutput){
213        if(!rc){
214          // force thread to time out
215          m_tResetOccurred=Now()-m_nReadTimeout;
216        }
217        CeCosThreadUtils::WaitFor(bThreadDone); // do not apply a timeout - the thread has one
218        rc=IsValidReset();
219        ResetLog(rc?_T("Reset output valid"):_T("Reset output INVALID"));
220      } 
221    } else {
222      ResetLog(String::SFormat(_T("Failed to contact reset server %s - %s"),(LPCTSTR)m_strHostPort,(LPCTSTR)sock.SocketErrString()));
223    }
224  } else {
225    // Sending something locally
226    m_tResetOccurred=Now();
227    unsigned int nWritten;
228    m_Serial.Write((void *)(LPCTSTR)m_strControl,1,nWritten);
229    if(bCheckOutput){
230      CeCosThreadUtils::WaitFor(bThreadDone);  // do not apply a timeout - the thread has one
231      rc=IsValidReset();
232      ResetLog(rc?_T("Reset output valid"):_T("Reset output INVALID"));
233    }
234  }
235
236  if(m_Socket.Ok()){
237    m_Socket.Close();
238  } else {
239    m_Serial.Close();
240  }
241  return rc && bCheckOutput;
242}
243
244// We expect to be passed a string that starts with "xxx(yyy)"
245// and the task is to extract xxx into strID and yyy into strArg
246const TCHAR *CResetAttributes::GetIdAndArg (LPCTSTR psz,String &strID,String &strArg)
247{
248  const TCHAR *cEnd=_tcschr(psz,_TCHAR('('));
249  if(cEnd){
250    strID=String(psz,cEnd-psz);
251    int nNest=0;
252    for(const TCHAR *c=cEnd;*c;c++){
253      if(_TCHAR('(')==*c){
254        nNest++;
255      } else if(_TCHAR(')')==*c){
256        nNest--;
257        if(0==nNest){
258          strArg=String(cEnd+1,c-(cEnd+1));
259          return c+1;
260        }
261      }
262    }
263    assert(false);
264  }
265  return 0;
266}
267
268// Do the reset
269CResetAttributes::ResetResult CResetAttributes::Reset (LogFunc *pfnLog, void *pfnLogparam,bool bCheckOnly)
270{
271  m_pfnReset=pfnLog;
272  m_pfnResetparam=pfnLogparam;
273
274  // First we clean up the reset string so as to make subsequent parsing less complicated.
275  // Spaces have already been removed in the ctor
276
277  // Check paren matching:
278  int nNest=0;
279  for(const TCHAR *c=m_str;*c;c++){
280    if(_TCHAR('(')==*c){
281      nNest++;
282    } else if(_TCHAR(')')==*c){
283      nNest--;
284      if(nNest<0){
285        ResetLog(_T("Too many right parentheses"));
286        return INVALID_STRING;
287      }
288    }
289  }
290  if(nNest>0){
291    ResetLog(_T("Too many left parentheses"));
292    return INVALID_STRING;
293  }
294
295  return Parse(m_str,bCheckOnly);
296}
297
298// This function parses the reset string, whose form is something like:
299//     expect($T05) 3(off(ginga:5000,a1) delay(2000) on(ginga:5000,a1,com1,38400,10000))
300// It is recursive (which is another reason elementary syntax checking was carried out above)
301// and calls itself to perform repeats [e.g. 3(...)]
302CResetAttributes::ResetResult CResetAttributes::Parse (LPCTSTR psz,bool bCheckOnly)
303{
304  enum {ARGSEP=_TCHAR(',')};
305  bool bCheck=false;
306  for(const TCHAR *c=psz;*c;){
307    String strID,strArg;
308    c=GetIdAndArg(c,strID,strArg);
309    if(0==c){
310      ResetLog(_T("Invalid reset string"));
311      return INVALID_STRING;
312    }
313
314    if(isdigit(*(LPCTSTR)strID)){
315      // Process a repeat-until-reset.  Syntax is n(resetstring)
316      int nRepeat=_ttoi(strID);
317      if(0==nRepeat){
318        ResetLog(_T("Invalid reset string"));
319        return INVALID_STRING;
320      }
321      if(bCheckOnly){
322        return Parse(strArg,true);
323      } else {
324        while(nRepeat--){
325          ResetResult r=Parse(strArg);
326          if(RESET_OK==r||INVALID_STRING==r){
327            return r;
328          }
329        }
330      }
331    } else if (_T("expect")==strID) {
332      //   Expected string(s).  e.g. expect(str1,str2,...).
333      strArg.Chop(m_arValidResetStrings,ARGSEP,true);
334    } else if (_T("port")==strID) {
335      // Port information.      e.g. port(com1,38400,1000)
336      // This information will apply to all subsequent actions until overwritten.
337      // Specifically args are:
338      //   0. Port
339      //   1. Baud
340      //   2. Read timeout
341      StringArray ar;
342      int nArgs=strArg.Chop(ar,ARGSEP,true);
343      if(nArgs>0){
344        m_strAuxPort=ar[0];
345      }
346      if(nArgs>1){
347        m_nBaud=_ttoi(ar[1]);
348      }
349      if(nArgs>2){
350        m_nReadTimeout=_ttoi(ar[2]);
351      }
352    } else if (_T("off")==strID || _T("on")==strID || _T("on_off")==strID || _T("off_on")==strID) {
353      // Action information.      e.g. off(ginga:500,A4,com1,38400,10000,1000)
354      // Specifically args are:
355      //   0. Reset host:port
356      //   1. Control string
357      //   2. Port
358      //   3. Baud
359      //   4. Read timeout
360      //   5. Delay
361      StringArray ar;
362      int nArgs=strArg.Chop(ar,ARGSEP,true);
363      if(nArgs>0){
364        m_strHostPort=ar[0]; 
365      }
366      if(nArgs>1){
367        m_strControl=ar[1];
368      }
369      if(nArgs>2){
370        m_strAuxPort=ar[2];
371      }
372      if(nArgs>3){
373        m_nBaud=_ttoi(ar[3]);
374      }
375      if(nArgs>4){
376        m_nReadTimeout=_ttoi(ar[4]);
377      }
378      if(nArgs>5){
379        m_nDelay=_ttoi(ar[5]);
380      }
381
382      if(0==m_strHostPort.size()){
383        ResetLog(_T("Failed to specify reset host:port"));
384        return INVALID_STRING;
385      }
386
387      Action action=ON; // prevent compiler warning
388      if(_T("on")==strID){
389        action=ON;
390      } else if(_T("off")==strID){
391        action=OFF;
392      } else if(_T("on_off")==strID){
393        action=ON_OFF;
394      } else if(_T("off_on")==strID){
395        action=OFF_ON;
396      } 
397
398      if(!bCheckOnly && Reset(action,bCheck||action==ON_OFF||action==OFF_ON)){
399        return RESET_OK;
400      }
401      bCheck ^= 1;
402    } else if (_T("delay")==strID) {
403      // Delay for a given time right now.      e.g. delay(1000)
404      // Specifically args are:
405      //   0. msec to delay
406      TRACE(_T("CeCosThreadUtils::Sleep %d\n"),_ttoi(strArg));
407      if(!bCheckOnly){
408        CeCosThreadUtils::Sleep(_ttoi(strArg));
409      }
410    } else {
411      ResetLog(String::SFormat(_T("Unrecognized command '%s'"),(LPCTSTR)strID));
412      return INVALID_STRING;
413    }
414  }
415  ResetLog(_T("Target reset not verified"));
416  return NOT_RESET;
417}
418
419// Log some output to the reset log function.
420void CResetAttributes::ResetLog(LPCTSTR psz)
421{
422  if(m_pfnReset){
423    ENTERCRITICAL;
424    m_pfnReset(m_pfnResetparam,String::SFormat(_T("%s >>> %s\n"),(LPCTSTR)CeCosTrace::Timestamp(),psz));
425    TRACE(_T("%s"),psz);
426    LEAVECRITICAL;
427  }
428}
429
430bool CResetAttributes::IsValidReset()
431{
432  unsigned int n=0;
433  ENTERCRITICAL;
434  for(int i=m_arValidResetStrings.size()-1;i>=0;--i){
435    if(_tcsstr(m_strResetOutput,m_arValidResetStrings[i])){
436      n++;
437    }
438  }
439  LEAVECRITICAL;
440  return n==m_arValidResetStrings.size();
441}
Note: See TracBrowser for help on using the repository browser.