1 //####COPYRIGHTBEGIN####
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
6 // This program is part of the eCos host tools.
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)
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
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.
22 // ----------------------------------------------------------------------------
24 //####COPYRIGHTEND####
25 //#####DESCRIPTIONBEGIN####
30 // Description: Holds information related to target reset
33 //####DESCRIPTIONEND####
35 #include "eCosThreadUtils.h"
36 #include "eCosTrace.h"
37 #include "ResetAttributes.h"
39 const CResetAttributes CResetAttributes::NoReset;
41 CResetAttributes::CResetAttributes(LPCTSTR psz) :
44 m_nReadTimeout(10*1000),
57 LPCTSTR CResetAttributes::Image(int nErr)
61 return _T("RESET_OK");
63 case RESET_ILLEGAL_DEVICE_CODE:
64 return _T("Illegal device code");
67 return _T("No reply from reset unit");
69 case RESET_BAD_CHECKSUM:
70 return _T("Bad checksum");
76 return _T("Unknown reset error");
81 void CResetAttributes::SuckThreadFunc()
83 m_strResetOutput=_T("");
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));
90 memset(buf,0,BUFSIZE); // safety for string functions in IsValidReset
92 unsigned int dwRead=0;
93 // We are working in non-blocking mode
95 if(!m_Socket.Peek(dwRead)||!m_Socket.recv(buf,MIN(dwRead,BUFSIZE))){
98 } else if (!m_Serial.Read(buf,BUFSIZE,dwRead)){
99 m_Serial.ClearError();
103 buf[dwRead]=_TCHAR('\0');
105 // Remove unprintable characters
107 for(const TCHAR *t=buf;*t;t++){
115 m_pfnReset(m_pfnResetparam,str);
120 m_strResetOutput+=str;
125 // } else { // Nothing read
126 // CeCosThreadUtils::Sleep(50);
128 } while (0==m_tResetOccurred || Now()-m_tResetOccurred<m_nReadTimeout);
130 if(0==m_strResetOutput.size()){
131 ResetLog(_T("No response from board"));
135 m_pfnReset(m_pfnResetparam,_T("\n"));
138 TRACE(_T("%s"),(LPCTSTR)m_strResetOutput);
142 bool CResetAttributes::Reset(Action action,bool bCheckOutput)
145 m_strResetOutput=_T("");
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);
153 strStatus+=_T(" expect(");
154 for(unsigned int i=0;i<m_arValidResetStrings.size();i++){
156 strStatus+=_TCHAR(',');
158 strStatus+=m_arValidResetStrings[i];
164 // Open up communication to port whence we read the board startup
165 bool bThreadDone=false;
166 bCheckOutput&=(m_strAuxPort.size()>0);
168 TRACE(_T("Opening %s\n"),(LPCTSTR)m_strAuxPort);
169 if(CeCosSocket::IsLegalHostPort(m_strAuxPort)){
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()));
177 m_Serial.SetBlockingReads(false);
178 if(m_Serial.Open(m_strAuxPort,m_nBaud)){
181 ResetLog(String::SFormat(_T("Failed to open comms port %s - %s"),(LPCTSTR)m_strAuxPort,(LPCTSTR)m_Serial.ErrString()));
185 CeCosThreadUtils::RunThread(SSuckThreadFunc,this,&bThreadDone,_T("SSuckThreadFunc"));
187 ResetLog(_T("[not checking output]"));
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);
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
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));
206 ResetLog(String::SFormat(_T("Failed to read response from reset server %s - %s"),(LPCTSTR)m_strHostPort,(LPCTSTR)sock.SocketErrString()));
209 ResetLog(String::SFormat(_T("Failed to contact reset server %s - %s"),(LPCTSTR)m_strHostPort,(LPCTSTR)sock.SocketErrString()));
211 m_tResetOccurred=Now();
214 // force thread to time out
215 m_tResetOccurred=Now()-m_nReadTimeout;
217 CeCosThreadUtils::WaitFor(bThreadDone); // do not apply a timeout - the thread has one
219 ResetLog(rc?_T("Reset output valid"):_T("Reset output INVALID"));
222 ResetLog(String::SFormat(_T("Failed to contact reset server %s - %s"),(LPCTSTR)m_strHostPort,(LPCTSTR)sock.SocketErrString()));
225 // Sending something locally
226 m_tResetOccurred=Now();
227 unsigned int nWritten;
228 m_Serial.Write((void *)(LPCTSTR)m_strControl,1,nWritten);
230 CeCosThreadUtils::WaitFor(bThreadDone); // do not apply a timeout - the thread has one
232 ResetLog(rc?_T("Reset output valid"):_T("Reset output INVALID"));
241 return rc && bCheckOutput;
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
246 const TCHAR *CResetAttributes::GetIdAndArg (LPCTSTR psz,String &strID,String &strArg)
248 const TCHAR *cEnd=_tcschr(psz,_TCHAR('('));
250 strID=String(psz,cEnd-psz);
252 for(const TCHAR *c=cEnd;*c;c++){
255 } else if(_TCHAR(')')==*c){
258 strArg=String(cEnd+1,c-(cEnd+1));
269 CResetAttributes::ResetResult CResetAttributes::Reset (LogFunc *pfnLog, void *pfnLogparam,bool bCheckOnly)
272 m_pfnResetparam=pfnLogparam;
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
277 // Check paren matching:
279 for(const TCHAR *c=m_str;*c;c++){
282 } else if(_TCHAR(')')==*c){
285 ResetLog(_T("Too many right parentheses"));
286 return INVALID_STRING;
291 ResetLog(_T("Too many left parentheses"));
292 return INVALID_STRING;
295 return Parse(m_str,bCheckOnly);
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(...)]
302 CResetAttributes::ResetResult CResetAttributes::Parse (LPCTSTR psz,bool bCheckOnly)
304 enum {ARGSEP=_TCHAR(',')};
306 for(const TCHAR *c=psz;*c;){
308 c=GetIdAndArg(c,strID,strArg);
310 ResetLog(_T("Invalid reset string"));
311 return INVALID_STRING;
314 if(isdigit(*(LPCTSTR)strID)){
315 // Process a repeat-until-reset. Syntax is n(resetstring)
316 int nRepeat=_ttoi(strID);
318 ResetLog(_T("Invalid reset string"));
319 return INVALID_STRING;
322 return Parse(strArg,true);
325 ResetResult r=Parse(strArg);
326 if(RESET_OK==r||INVALID_STRING==r){
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:
342 int nArgs=strArg.Chop(ar,ARGSEP,true);
347 m_nBaud=_ttoi(ar[1]);
350 m_nReadTimeout=_ttoi(ar[2]);
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
362 int nArgs=strArg.Chop(ar,ARGSEP,true);
373 m_nBaud=_ttoi(ar[3]);
376 m_nReadTimeout=_ttoi(ar[4]);
379 m_nDelay=_ttoi(ar[5]);
382 if(0==m_strHostPort.size()){
383 ResetLog(_T("Failed to specify reset host:port"));
384 return INVALID_STRING;
387 Action action=ON; // prevent compiler warning
390 } else if(_T("off")==strID){
392 } else if(_T("on_off")==strID){
394 } else if(_T("off_on")==strID){
398 if(!bCheckOnly && Reset(action,bCheck||action==ON_OFF||action==OFF_ON)){
402 } else if (_T("delay")==strID) {
403 // Delay for a given time right now. e.g. delay(1000)
404 // Specifically args are:
406 TRACE(_T("CeCosThreadUtils::Sleep %d\n"),_ttoi(strArg));
408 CeCosThreadUtils::Sleep(_ttoi(strArg));
411 ResetLog(String::SFormat(_T("Unrecognized command '%s'"),(LPCTSTR)strID));
412 return INVALID_STRING;
415 ResetLog(_T("Target reset not verified"));
419 // Log some output to the reset log function.
420 void CResetAttributes::ResetLog(LPCTSTR psz)
424 m_pfnReset(m_pfnResetparam,String::SFormat(_T("%s >>> %s\n"),(LPCTSTR)CeCosTrace::Timestamp(),psz));
430 bool CResetAttributes::IsValidReset()
434 for(int i=m_arValidResetStrings.size()-1;i>=0;--i){
435 if(_tcsstr(m_strResetOutput,m_arValidResetStrings[i])){
440 return n==m_arValidResetStrings.size();