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 //=================================================================
31 //=================================================================
32 //=================================================================
33 //#####DESCRIPTIONBEGIN####
38 // Description: This class abstracts a test for use in the testing infrastructure
41 //####DESCRIPTIONEND####
42 ///////////////////////////////////////////////////////////////////////////////
45 #include "eCosTestPlatform.h"
46 #include "eCosTrace.h"
47 #include "TestResource.h"
48 #include "eCosTestUtils.h"
49 #include "eCosSocket.h"
50 #include "eCosSerial.h"
51 #include "eCosTestSerialFilter.h"
52 #include "eCosTestDownloadFilter.h"
53 #include "Properties.h"
54 #include "Subprocess.h"
56 #define WF(n) (n+50)/1000,((n+50)%1000)/100 // Present n as whole and fractional part. Round to nearest least significant digit
57 #define WFS _T("%u.%u") // The format string to output the above
59 LPCTSTR const CeCosTest::arResultImage[1+CeCosTest::StatusTypeMax]=
60 {_T("NotStarted"), _T("NoResult"), _T("Inapplicable"), _T("Pass"), _T("DTimeout"), _T("Timeout"), _T("Cancelled"), _T("Fail"), _T("AssertFail"), _T("Unknown")};
62 CeCosTest *CeCosTest::pFirstInstance=0;
63 int CeCosTest::InstanceCount=0;
65 LPCTSTR const CeCosTest::arServerStatusImage[1+CeCosTest::ServerStatusMax]={
66 _T("Busy"), _T("Ready"), _T("Can't run"), _T("Connection failed"), _T("Locked"), _T("Bad server status")};
67 LPCTSTR CeCosTest::ExecutionParameters::arRequestImage [1+ExecutionParameters::RequestTypeMax]={
68 _T("Run"), _T("Query"), _T("Lock"), _T("Unlock"), _T("Stop"), _T("Bad request") };
70 static bool CALLBACK IsCancelled(void *pThis)
72 return CeCosTest::Cancelled==((CeCosTest *)pThis)->Status();
76 CeCosTest::CeCosTest(const ExecutionParameters &e, LPCTSTR pszExecutable,LPCTSTR pszTitle):
80 m_bDownloading(false),
87 m_nMaxInactiveTime(0),
94 SetExecutable (pszExecutable);
96 TRACE(_T("%%%% Create test instance %08x count:=%d\n"),this,InstanceCount+1);
98 // By recording the path now, we ensure processes are always run in the context in which the test instance
99 // is created (important for the ConfigTool to be able to call PrepareEnvironment).
102 // for some reason _tgetenv() doesn't return the PATH set
103 // by PrepareEnvironment() so use GetEnvironmentVariable() instead
106 int nSize=GetEnvironmentVariable(_T("PATH"), NULL, 0);
107 GetEnvironmentVariable(_T("PATH"), strPath.GetBuffer(nSize), nSize);
108 strPath.ReleaseBuffer();
111 LPCTSTR pszPath=_tgetenv(_T("PATH"));
119 m_pNextInstance=pFirstInstance;
121 m_pNextInstance->m_pPrevInstance=this;
129 CeCosTest::~CeCosTest()
131 for(int i=0;i<(signed)m_arpExecsp.size();i++){
132 delete (CSubprocess *)m_arpExecsp[i];
136 TRACE(_T("%%%% Delete test instance %08x\n"),this);
140 m_pResource->Release();
141 //delete m_pResource;
145 VTRACE(_T("~CeCosTest(): EnterCritical and decrease instance count\n"));
148 TRACE(_T("%%%% Destroy instance. Instance count:=%d\n"),InstanceCount);
149 if(pFirstInstance==this){
150 pFirstInstance=m_pNextInstance;
153 m_pPrevInstance->m_pNextInstance=m_pNextInstance;
156 m_pNextInstance->m_pPrevInstance=m_pPrevInstance;
161 bool CeCosTest::RunRemote (LPCTSTR pszRemoteHostPort)
164 TRACE(_T("RunRemote\n"));
165 m_strExecutionHostPort=pszRemoteHostPort;
168 VTRACE(_T("RemoteThreadFunc()\n"));
171 ConnectForExecution();
172 if(Cancelled!=Status()){
173 if(m_ep.Platform()->ServerSideGdb()){
174 // The executable is transmitted to the server for execution.
176 if(m_pSock->sendInteger(m_nFileSize,_T("file size"))&&m_nFileSize>0){
177 int nBufSize=MIN(10000,m_nFileSize);
179 TRACE(_T("Sending [%d bytes]\n"), m_nFileSize);
180 int nToSend=m_nFileSize;
181 FILE *f1=_tfopen(m_strExecutable,_T("rb"));
183 Log(_T("Failed to open %s - %s\n"),(LPCTSTR)m_strExecutable,strerror(errno));
186 int nRead=fread( b.Data(), 1, nBufSize, f1);
188 Log(_T("Failure reading %s - %s\n"),(LPCTSTR)m_strExecutable,strerror(errno));
191 if(!send( b.Data(), nRead, _T("executable"))){
192 Log(_T("Failure sending %s - %s\n"),(LPCTSTR)m_strExecutable,(LPCTSTR)m_pSock->SocketErrString());
200 TRACE(_T("done [%d bytes sent]\n"),m_nFileSize-nToSend);
201 Log(_T("Failed to transmit %s - %d/%d bytes sent\n"),(LPCTSTR)m_strExecutable,m_nFileSize-nToSend,m_nFileSize);
207 if(!recvResult(9*1000*60)){ // nine minutes
208 Log(_T("Failed to receive result from remote server\n"));
211 m_pSock->sendInteger(456); // send an ack [n'importe quoi]
215 // The server sets up a connection between port and tcp/ip socket, and gdb is run locally
216 // Big timeout here because we have to wait for the target to be reset
219 // target ready indicator (0==fail, 1==ready, 2==fail and will retry)
221 // } while (2==target ready indicator)
224 if(GetTargetReady(strHostPort)){
225 // Fix up a resource to represent permission to use the host:port we have been told about
226 CTestResource resource;
227 resource.SetTarget(m_ep.PlatformName());
228 resource.SetDownload(strHostPort,0);
229 m_pResource=&resource;
232 m_pSock->sendInteger(Status(),_T("Terminating ack"));
238 TRACE(_T("RemoteThreadFunc - exiting\n"));
242 // Run the test locally
243 bool CeCosTest::RunLocal()
247 TRACE(_T("RunLocal %s\n"),(LPCTSTR)Executable());
249 if(!CeCosTestUtils::IsFile(Executable())){
250 Log(_T("Cannot run - %s is not a file\n"),(LPCTSTR)Executable());
251 } else if(0==m_pResource && 0==CTestResource::Count(m_ep)){
252 Log(_T("Cannot run a %s test\n"),(LPCTSTR)m_ep.PlatformName());
257 TRACE(_T("LocalThreadFunc - target=%s\n"),(LPCTSTR)m_ep.PlatformName());
258 // Acquire a port (our caller may have done this for us)
259 VTRACE(_T("LocalThreadFunc():Trying to acquire a port\n"));
262 m_pResource=CTestResource::GetResource(m_ep);
263 if(m_pResource||Cancelled==Status()){
266 CeCosThreadUtils::Sleep(2000);
267 TRACE(_T("Waiting for a port\n"));
270 VTRACE(_T("\nPort acquired!\n"));
272 if(Cancelled!=Status()){
273 // This means we have acquired a local port
274 bool bTargetReady=false;
275 if(!m_pResource->HasReset()){
278 bTargetReady=(CResetAttributes::RESET_OK==m_pResource->Reset(0,this));
280 // we may proceed to execute the test
282 SetStatus(NotStarted);
284 if(NOTIMEOUT==m_ep.DownloadTimeout()){
285 // No elapsed timeout given - calculate from knowledge of executable size and baud rate
286 // 10 baud ~= 1 byte/sec, but we halve this to account for download in hex :-(
287 // We use a minimum of 30 seconds and double the calculated result for safety
288 // Note that the baud rate is generally unknown on the client side.
289 int nBaud=m_pResource->Baud();
291 CTestResource *pExecutionResource=CTestResource::Lookup(m_strExecutionHostPort);
292 if(pExecutionResource){
293 nBaud=pExecutionResource->Baud();
300 int nBytesPerSec=(nBaud/10)/2; // division by 2 assumes download in "ascii" (2 bytes/char)
301 m_ep.SetDownloadTimeout (1000*MAX(30,2*(m_nStrippedSize/nBytesPerSec)));
302 TRACE(_T("Estimated download time %d sec (%d bytes @ %d bytes/sec [%d baud])\n"),m_nStrippedSize/nBytesPerSec,m_nStrippedSize,nBytesPerSec,nBaud);
305 TRACE(_T("Active timeout=%d download timeout=%d\n"),m_ep.ActiveTimeout(), m_ep.DownloadTimeout());
307 GetInferiorCommands(m_arstrInferiorCmds);
308 String strInferior(m_ep.Platform()->Inferior());
309 strInferior.Replace(_T("%e"),CygPath(m_strExecutable),true);
310 RunInferior(strInferior);
315 m_pResource->Release();
318 TRACE(_T("RunLocal - exiting\n"));
324 void CeCosTest::Cancel ()
326 SetStatus(Cancelled);
329 CeCosTest::ServerStatus CeCosTest::Connect (LPCTSTR pszHostPort, CeCosSocket *&pSock, const ExecutionParameters &e,String &strInfo,Duration dTimeout)
331 // Find out whether this host is receptive
332 ServerStatus s=CONNECTION_FAILED;
333 pSock=new CeCosSocket(pszHostPort,dTimeout);
336 pSock->sendString(e.Image(), _T("execution parameters")) &&
337 pSock->recvInteger(nStatus,_T("ready status")) &&
338 pSock->recvString(strInfo)){
339 s=(ServerStatus)MIN(nStatus,ServerStatusMax);
341 if(SERVER_READY!=s || ExecutionParameters::RUN!=e.Request()){
348 // Initiate a connection to hostName:nPort and acquire the ready status [retry until this is achieved]
349 // The socket (m_pSock) is left open.
350 // This function is either called with m_strExecutionHostPort already set to a desired server
351 // or else m_strExecutionHostPort empty (in which case the server is / dynamically)
353 void CeCosTest::ConnectForExecution ()
355 bool bSchedule=(0==m_strExecutionHostPort.size());
356 Duration nDelay=2000;
360 bool *arbHostTried=0;
362 while(Cancelled!=Status()){
363 StringArray arstrHostPort,arstrTries;
367 if(!CTestResource::GetMatches(m_ep,arstrHostPort)){
368 Log(_T("Could not establish matches\n"));
371 nChoices=arstrHostPort.size();
373 TRACE(_T("ConnectForExecution: choices are:\n"));
374 for(int i=0;i<nChoices;i++){
375 TRACE(_T("\t%s\n"),(LPCTSTR)arstrHostPort[i]);
379 // Server has already been picked by caller
382 arstrHostPort.push_back(m_strExecutionHostPort);
386 delete [] arbHostTried;
387 arbHostTried=new bool[nChoices];
388 for(int i=0;i<nChoices;i++){
389 arbHostTried[i]=false;
392 // Loop around the choices
393 for(int nUntried=nChoices;nUntried>0;nUntried--) {
394 // Select one we haven't tried already:
397 nChoice=rand() % nChoices;
398 } while (arbHostTried[nChoice]);
400 m_strExecutionHostPort=arstrHostPort[nChoice];
402 TRACE(_T("ConnectForExecution: chosen %s\n"),(LPCTSTR)m_strExecutionHostPort);
403 if(CeCosSocket::IsLegalHostPort(m_strExecutionHostPort)){
404 // If we're using the resource server we had better check that the host
405 // we are about to lock has not been resource-locked (the other match checks
406 // will of course always succeed)
408 ServerStatus s=bSchedule && !CTestResource::Matches(m_strExecutionHostPort,m_ep)?SERVER_LOCKED:
409 Connect(m_strExecutionHostPort,m_pSock,m_ep,strInfo);
410 arbHostTried[nChoice]=true;
411 TRACE(_T("Connect: %s says %s %s\n"),(LPCTSTR)m_strExecutionHostPort,(LPCTSTR)Image(s),(LPCTSTR)strInfo);
412 CTestResource *pResource=CTestResource::Lookup(m_strExecutionHostPort);
415 str.Format(_T("%s %s %s"),(LPCTSTR)pResource->Image(),(LPCTSTR)strInfo,(LPCTSTR)Image(s));
416 arstrTries.push_back(str);
419 // So that's ok then. We're outta here.
420 INTERACTIVE(_T("Connected to %s\n"),(LPCTSTR)m_strExecutionHostPort);
430 INTERACTIVE(_T("Warning - could not connect to any test servers:\n"));
431 if(arstrTries.size()>0){
432 for(unsigned int i=0;i<arstrTries.size();i++){
433 INTERACTIVE(_T(" %s\n"),(LPCTSTR)arstrTries[i]);
436 INTERACTIVE(_T("No servers available to execute %s test:\n"),(LPCTSTR)m_ep.PlatformName());
438 for(CTestResource *pResource=CTestResource::First();pResource;pResource=pResource->Next()){
439 INTERACTIVE(_T(" %s\n"),(LPCTSTR)pResource->Image());
443 INTERACTIVE(_T("Retry in %d seconds...\n"),nDelay/1000);
445 // We have tried all possibilities - sleep before retrying
446 CeCosThreadUtils::Sleep(nDelay);
448 if(Cancelled==m_Status){
449 TRACE(_T("ConnectForExecution : cancelled\n"));
453 nDelay+=rand() % 500;
457 delete [] arbHostTried;
460 void CeCosTest::SetStatus (StatusType status)
463 if((int)status>(int)m_Status){
464 TRACE(_T("Status <- %s\n"),(LPCTSTR)Image(status));
470 bool CeCosTest::WaitForAllInstances(int nPoll,Duration nTimeout)
473 while(InstanceCount>0){
474 CeCosThreadUtils::Sleep(nPoll);
475 if(NOTIMEOUT!=nTimeout && Now()-t0>nTimeout){
482 void CeCosTest::DeleteAllInstances()
484 while(pFirstInstance){
485 delete pFirstInstance;
489 void CeCosTest::CancelAllInstances()
492 for(CeCosTest *pTest=pFirstInstance;pTest;pTest=pTest->m_pNextInstance){
498 // The same format is used for _stscanf as for Format (which is like printf), so restrict to the format specifiers
499 // the former is happy with. In particular, do not use %-3s etc...
501 LPCTSTR CeCosTest::pszFormat=
502 // 1999-01-15 17:24:36 Fireblade:5002 MN10300 sin.exe 219k/134k Pass sin download=106.3/117.0 Total=107.6 Max inactive=1.0/300.0
503 _T("%04d-%02d-%02d %02d:%02d:%02d ") // Time
504 _T("%15s ") // Execution host:port
505 _T("%16s ") // Target
506 _T("%30s ") // Executable tail
507 _T("%11s ") // Result
508 _T("%dk/%dk ") // Sizes
509 _T("D=") WFS _T("/") WFS _T(" Total=") WFS _T(" ") // Times
510 _T("E=") WFS _T("/") WFS _T(" ")
513 bool CeCosTest::Value (
518 String &strExecutionHostPort,
519 String &strExecutableTail,
523 Duration &nTotalTime,
524 Duration &nMaxInactiveTime,
525 Duration &nDownloadTime,
526 Duration &nDownloadTimeout,
527 Duration &nActiveTimeout,
529 int &nDownloadedSize)
531 int nLen=_tcslen(pszStr);
534 nFileSize=nTotalTime=nMaxInactiveTime=nDownloadTime=nDownloadTimeout=nActiveTimeout=nDownloadedSize=0;
536 int nTotalTimeFrac=0;
537 int nMaxInactiveTimeFrac=0;
538 int nActiveTimeoutFrac=0;
539 int nDownloadTimeFrac=0;
540 int nDownloadTimeoutFrac=0;
542 static String strFormat;
543 if(0==strFormat.size()){
544 // Construct a version of the format string sans length attributes for %s items
546 TCHAR *d=strFormat.GetBuffer(_tcslen(pszFormat));
547 while(_TCHAR('\0')!=*c){
548 if(_TCHAR('%')==c[0] && _istdigit(c[1])){
552 } while (_istdigit(*c));
557 strFormat.ReleaseBuffer();
562 &t.tm_year,&t.tm_mon,&t.tm_mday,
563 &t.tm_hour,&t.tm_min,&t.tm_sec, // Time of day
564 strExecutionHostPort.GetBuffer(1+nLen), // Execution host:port
565 target.GetBuffer(1+nLen), // Target
566 strExecutableTail.GetBuffer(1+nLen), // Executable
567 strStatus.GetBuffer(1+nLen), // Result
568 &nDownloadedSize,&nFileSize, // Sizes
569 &nDownloadTime,&nDownloadTimeFrac, // Times
570 &nDownloadTimeout,&nDownloadTimeoutFrac,
571 &nTotalTime,&nTotalTimeFrac,
572 &nMaxInactiveTime,&nMaxInactiveTimeFrac,
573 &nActiveTimeout,&nActiveTimeoutFrac,
574 strTitle.GetBuffer(1+nLen) // Title
577 strExecutionHostPort.ReleaseBuffer();
578 target.ReleaseBuffer();
579 strExecutableTail.ReleaseBuffer();
580 strStatus.ReleaseBuffer();
581 strTitle.ReleaseBuffer();
582 status=StatusTypeValue(strStatus);
584 LPCTSTR c1=_tcschr(pszStr,_TCHAR('"'));
587 LPCTSTR c2=_tcschr(c1+1,_TCHAR('"'));
589 strTitle=String(c1,c2-c1);
593 nTotalTime=nTotalTime*1000+nTotalTimeFrac*100;
594 nMaxInactiveTime=nMaxInactiveTime*1000+nMaxInactiveTimeFrac*100;
595 nActiveTimeout=nActiveTimeout*1000+nActiveTimeoutFrac*100;
596 nDownloadTime=nDownloadTime*1000+nDownloadTimeFrac*100;
597 nDownloadTimeout=nDownloadTimeout*1000+nDownloadTimeoutFrac*100;
600 nDownloadedSize*=1024;
603 return t.tm_year>=0 && t.tm_year<=200 && t.tm_mon>=0 && t.tm_mon<=11 && t.tm_mday>=1 && t.tm_mday<=31 && t.tm_hour>=0 && t.tm_hour<=23 && t.tm_min>=0 && t.tm_min<=59 && t.tm_sec>=0 && t.tm_sec<=59 &&
604 status!=StatusTypeMax
605 //&& exetype!=ExecutionParameters::ExecutableTypeMax
609 const String CeCosTest::ResultString(bool bIncludeOutput) const
611 String strResultString;
612 String strTitle(m_strTitle);
613 String strExecutionHostPort(m_strExecutionHostPort);
615 if(0==strTitle.size()){
616 strTitle=CeCosSocket::MySimpleHostName();
617 strTitle+=_TCHAR(':');
618 strTitle+=m_strExecutable;
621 if(0==strExecutionHostPort.size()){
622 strExecutionHostPort=CeCosSocket::MySimpleHostName();
623 strExecutionHostPort+=_T(":0");
629 struct tm *now=localtime( <ime );
631 strResultString.Format(
633 1900+now->tm_year,1+now->tm_mon,now->tm_mday,
634 now->tm_hour,now->tm_min,now->tm_sec, // Time of day
635 (LPCTSTR)strExecutionHostPort, // Execution host:port
636 (LPCTSTR)m_ep.PlatformName(), // Target
637 (LPCTSTR)CeCosTestUtils::Tail(m_strExecutable), // Executable
638 (LPCTSTR)Image(Status()), // Result
639 m_nStrippedSize/1024,m_nFileSize/1024, // Sizes
640 WF(m_nDownloadTime),WF(m_ep.DownloadTimeout()),WF(m_nTotalTime),// Times
641 WF(m_nMaxInactiveTime),WF(m_ep.ActiveTimeout()),
642 (LPCTSTR)strTitle // Title
644 if(bIncludeOutput && m_strOutput.size()>0){
645 strResultString+=_TCHAR('\n');
646 strResultString+=m_strOutput;
649 return strResultString;
652 // Run as a server, listening on the port given as parameter
653 bool CeCosTest::RunAgent(int nTcpPort)
658 int nSock = CeCosSocket::Listen(nTcpPort);
663 CeCosSocket *pSock=new CeCosSocket(nSock); // AcceptThreadFunc deletes if not deleted below
665 // Read the execution parameters
666 if(!pSock->recvString(str)){
667 // Socket error on the recv - nothing much we can do
668 TRACE(_T("RunAgent : could not read execution parameters\n"));
672 ExecutionParameters e;
674 TRACE(_T("Execution parameters: %s\n"),(LPCTSTR)e.Image());
676 CTestResource *pPort=0;
679 switch(e.Request()) {
680 case ExecutionParameters::LOCK:
684 WaitForAllInstances(1000,NOTIMEOUT);
689 case ExecutionParameters::UNLOCK:
697 case ExecutionParameters::QUERY:
703 for(CTestResource *pResource=CTestResource::First();pResource;pResource=pResource->Next()){
704 if(!pResource->InUse()){
711 strInfo.Format(_T("serving %s"),(LPCTSTR)CeCosSocket::ClientName(nLastClient));
715 case ExecutionParameters::RUN:
716 if(NULL==e.Platform()){
717 // Looks like a confused client ...
718 strInfo.Format(_T("Bad target value %s read from client\n"),(LPCTSTR)str);
720 } else if(0==CTestResource::Count(e)){
721 // No chance of running this test
722 strInfo.Format(_T("Cannot run a %s test from this server\n"),(LPCTSTR)e.PlatformName());
724 } else if (bLocked) {
727 pPort=CTestResource::GetResource(e);
729 // We must disappoint our client
730 strInfo.Format(_T("serving %s"),(LPCTSTR)CeCosSocket::ClientName(nLastClient));
734 nLastClient=pSock->Client();
738 case ExecutionParameters::STOP:
746 if(ExecutionParameters::QUERY!=e.Request())
748 TRACE(_T("RunAgent : %s request tActive=%d tDownload=%d Target=%s Reply status=%s %s\n"),
749 (LPCTSTR)e.Image(e.Request()),e.ActiveTimeout(),e.DownloadTimeout(),
750 (LPCTSTR)e.PlatformName(),
751 (LPCTSTR)Image(s),(LPCTSTR)strInfo);
753 bool bSendok=pSock->sendInteger(s) && pSock->sendString(strInfo);
755 if(SERVER_READY==s && bSendok && ExecutionParameters::RUN==e.Request()){
757 // Create a new class instance
758 // AcceptThreadFunc deletes the instance and closes new_sock
759 // RunLocal, called by AcceptThreadFunc, releases the port
760 // No need for meaningful callback, but must run asynchronously
763 int nAuxListenSock=-1;
766 nAuxListenSock=CeCosSocket::Listen(nAuxPort);
767 } while (-1==nAuxListenSock && nAuxPort++<=0xffff);
769 if(-1==nAuxListenSock){
770 ERROR(_T("Couldn't find a socket to bind to for RDI\n"));
773 CeCosTest *pTest=new CeCosTest(e,NULL);
774 pTest->m_nAuxPort=nAuxPort;
775 pTest->m_nAuxListenSock=nAuxListenSock;
776 pTest->m_pSock=pSock;
777 pTest->m_strExecutionHostPort=CeCosSocket::HostPort(CeCosSocket::MyHostName(),nTcpPort);
778 pTest->m_pResource=pPort;
779 CeCosThreadUtils::RunThread(SAcceptThreadFunc,pTest,_T("SAcceptThreadFunc"));
780 // AcceptThreadFunc deletes pSock
790 if(CeCosTest::ExecutionParameters::STOP==e.Request()){
791 CancelAllInstances();
792 WaitForAllInstances(1000,20*1000);
799 TRACE(_T("!!! Exception caught in RunAgent()\n"));
802 CeCosSocket::CloseSocket (nSock);
808 CeCosTest::StatusType CeCosTest::StatusTypeValue(LPCTSTR pszStr)
810 for(int i=0;i<StatusTypeMax;i++){
811 StatusType t=(StatusType)i;
812 if(0==_tcsicmp(Image(t),pszStr)){
816 return StatusTypeMax;
819 // Thread to run ConnectSocketToSerial
820 void CeCosTest::ConnectSocketToSerialThreadFunc()
822 TRACE(_T("ConnectSocketToSerialThreadFunc sock=%d\n"),m_nAuxListenSock);
824 CeCosTestSerialFilter serial_filter;
825 CeCosTestDownloadFilter download_filter;
828 serial.SetBlockingReads(false);
830 // Open serial device.
831 if (!serial.Open(m_pResource->Serial(),m_pResource->Baud())){
832 ERROR(_T("Couldn't open port %s\n"),m_pResource->Serial());
835 // Flush the serial buffer.
837 TRACE(_T("ConnectSocketToSerial: waiting for connection...\n"));
839 if(!socket.Accept(m_nAuxListenSock,&m_bStopConnectSocketToSerial)){
840 ERROR(_T("ConnectSocketToSerial - couldn't accept: %s\n"),(LPCTSTR)socket.SocketErrString());
842 } else if (m_pSock->Client() != socket.Client()){
843 // Make sure the client is who we think it is...
844 TRACE(_T("ConnectSocketToSerialThread - illegal connection attempted from %s\n"),(LPCTSTR)socket.ClientName(socket.Client()));
847 rc=CeCosSocket::ConnectSocketToSerial(socket,serial,m_ep.m_bUseFilter?SerialFilterFunction:NULL, (void*)&serial_filter, m_ep.m_bUseFilter?DownloadFilterFunction:NULL, (void*)&download_filter, &m_bStopConnectSocketToSerial);
849 // If the download filter was just active, it may
850 // allow the session to continue.
851 if(!download_filter.ContinueSession()){
856 catch (LPCTSTR pszMsg){
857 Log(_T("!!! ConnectSocketToSerial exception caught: %s!!!\n"),pszMsg);
862 Log(_T("!!! ConnectSocketToSerial exception caught!!!\n"));
869 TRACE(_T("ConnectSocketToSerial : done\n"));
870 CeCosSocket::CloseSocket(m_nAuxListenSock);
873 static bool CALLBACK DerefBool(void *pParam)
875 return *(bool *)pParam;
878 // Function called (on a separate thread) to process a successful connection to the RunAgent loop
879 // In the case of a simulator server, we can have many of these active at the same time.
880 void CeCosTest::AcceptThreadFunc()
882 if(m_ep.Platform()->ServerSideGdb()){
883 // We dream up a temporary name for the executable
885 m_strExecutable.Format(_T("%s-%s-%d"),_ttmpnam(0),(LPCTSTR)m_ep.PlatformName(),m_nAuxPort);
889 if(m_pSock->recvInteger(n,_T("file size"))){
891 // Read file from the socket
893 TRACE(_T("AcceptThreadFunc file size=%d reading...\n"),m_nFileSize);
895 f2=_tfopen(m_strExecutable,_T("wb"));
897 Log(_T("Could not create %s - %s\n"),(LPCTSTR)m_strExecutable,strerror(errno));
900 unsigned int nBufSize=MIN(100000,m_nFileSize);
902 unsigned int nWritten=0;
903 unsigned int nRead=0;
904 while(nRead<m_nFileSize){
905 int nToRead=MIN(nBufSize,m_nFileSize-nRead);
906 if(!recv( b.Data(), nToRead, _T("executable"))){
911 char *c=(char *)b.Data();
913 int w=fwrite(c,1,nToRead,f2);
915 Log(_T("Write error on %s - %s\n"),(LPCTSTR)m_strExecutable,strerror(errno));
925 TRACE(_T("Accept - done reading [%d bytes read, %d bytes written]\n"),nRead,nWritten);
928 _tchmod(m_strExecutable,00700); // user read, write and execute
930 if(0!=f2 && m_nFileSize!=nWritten){
931 Log(_T("Failed to create %s correctly [%d/%d bytes written]\n"),(LPCTSTR)m_strExecutable, nWritten, m_nFileSize);
934 SetExecutable(m_strExecutable); // to set stripped length and title
936 _tunlink(m_strExecutable);
939 m_pSock->recvInteger(n); // receive an ack
943 if(_TCHAR('\0')==*(m_pResource->ResetString())){
945 TRACE(_T("No reset possible\n"));
947 Log(_T("Resetting target using %s"),(LPCTSTR)m_pResource->ResetString());
948 bTargetReady=(CResetAttributes::RESET_OK==m_pResource->Reset(ResetLogFunc,this));
950 TRACE(_T("Send Target Ready indicator=%d\n"),bTargetReady);
951 m_pSock->sendInteger(bTargetReady,_T("target ready indicator"));
956 if(CeCosSocket::IsLegalHostPort(m_pResource->Serial())){
957 TRACE(_T("Sending %s\n"),(LPCTSTR)m_pResource->Serial());
958 if(m_pSock->sendString(m_pResource->Serial(),_T("Serial name")) && m_pSock->recvInteger(nAck,_T("Terminating ack"),CeCosSocket::NOTIMEOUT)){
959 TRACE(_T("Terminating ack=%d\n"),nAck);
962 String strHostPort(CeCosSocket::HostPort(CeCosSocket::MyHostName(),m_nAuxPort));
964 TRACE(_T("Using %s\n"),(LPCTSTR)strHostPort);
966 if(m_pSock->sendString(strHostPort,_T("host:port"))){
968 // This Boolean signifies that the serial<-->tcp/ip conversation is done. It may be set
969 // on completion of the ConnectSocketToSerial thread (which is why we pass it to runthread)
970 // and also set by us to *cause* the thread to complete.
972 bool bConnectSocketToSerialThreadDone=false; // Indication of termination of ConnectSocketToSerial thread
973 m_bStopConnectSocketToSerial=false; // Used to tap ConnectSocketToSerial thread on the shoulder
975 CeCosThreadUtils::RunThread(SConnectSocketToSerialThreadFunc,this,&bConnectSocketToSerialThreadDone,_T("SConnectSocketToSerialThreadFunc"));
977 // Wait for either client or the ConnectSocketToSerial thread to finish.
978 if(m_pSock->recv(&nAck,sizeof(int),_T("Terminating ack"),CeCosSocket::NOTIMEOUT,DerefBool,&bConnectSocketToSerialThreadDone)){
979 TRACE(_T("Session terminated by request of client (%s)\n"),(LPCTSTR)Image((StatusType)nAck));
980 } else if(0!=m_pSock->SocketError()){
981 TRACE(_T("Session terminated by socket error - %s\n"),(LPCTSTR)m_pSock->SocketErrString());
983 if(!bConnectSocketToSerialThreadDone){
984 // Tap ConnectSocketToSerial thread on the shoulder
985 TRACE(_T("Waiting for ConnectSocketToSerial thread to terminate...\n"));
986 m_bStopConnectSocketToSerial=true;
987 CeCosThreadUtils::WaitFor(bConnectSocketToSerialThreadDone);
996 bool CeCosTest::send(const void *pData,unsigned int nLength,LPCTSTR pszMsg,Duration dTimeout)
998 return m_pSock->send(pData,nLength,pszMsg,dTimeout,IsCancelled,this);
1001 bool CeCosTest::recv(const void *pData,unsigned int nLength,LPCTSTR pszMsg,Duration dTimeout)
1003 return m_pSock->recv(pData,nLength,pszMsg,dTimeout,IsCancelled,this);
1006 void CeCosTest::Log(LPCTSTR pszFormat, ...)
1009 va_start(args, pszFormat);
1011 str.vFormat(pszFormat,args);
1016 void CeCosTest::LogString(LPCTSTR psz)
1022 if(CeCosTrace::IsInteractive()){
1023 CeCosTrace::Out(psz);
1025 TRACE(_T("%s"),psz);
1030 bool CeCosTest::sendResult(Duration dTimeout)
1033 m_pSock->sendInteger(m_Status,_T("result"),dTimeout) &&
1034 m_pSock->sendInteger(m_nDownloadTime,_T("result"),dTimeout) &&
1035 m_pSock->sendInteger(m_nTotalTime,_T("result"),dTimeout) &&
1036 m_pSock->sendInteger(m_nMaxInactiveTime,_T("result"),dTimeout) &&
1037 m_pSock->sendString (m_strOutput,_T("result"),dTimeout);
1041 bool CeCosTest::recvResult(Duration dTimeout)
1044 int nStatus=StatusTypeMax;
1046 m_pSock->recvInteger(nStatus,_T("result"),dTimeout) &&
1047 m_pSock->recvInteger(m_nDownloadTime,_T("result"),dTimeout) &&
1048 m_pSock->recvInteger(m_nTotalTime,_T("result"),dTimeout) &&
1049 m_pSock->recvInteger(m_nMaxInactiveTime,_T("result"),dTimeout) &&
1050 m_pSock->recvString (strOutput,_T("result"),dTimeout);
1051 m_Status=(StatusType)MIN(nStatus,StatusTypeMax);
1052 LogString(strOutput);
1056 // Return time used by inferior gdb process - CPU for sim, wallclock otherwise
1057 Time CeCosTest::InferiorTime() const
1059 if(*(m_pResource->Serial())){
1066 if(now-m_tPrevSample>1000){
1068 m_tInferiorCpuTime=m_psp->CpuTime();
1070 return m_tInferiorCpuTime;
1073 bool CeCosTest::CheckForTimeout()
1075 bool rc=(Cancelled!=Status());
1076 if(TimeOut!=m_Status && DownloadTimeOut!=m_Status){
1077 Time t=InferiorTime();
1079 // We have been able to measure the time
1081 m_nDownloadTime=MAX(m_nDownloadTime,Duration(InferiorTime()-m_tBase));
1082 if(m_nDownloadTime>m_ep.DownloadTimeout()){
1083 Log(_T("\n*** Timeout - download time ") WFS _T(" exceeds limit of ") WFS _T("\n"),WF(m_nDownloadTime),WF(m_ep.DownloadTimeout()));
1087 m_nMaxInactiveTime=MAX(m_nMaxInactiveTime,Duration(InferiorTime()-m_tBase));
1088 if (m_nMaxInactiveTime>m_ep.ActiveTimeout()) {
1089 Log(_T("\n*** Timeout - inactive time ") WFS _T(" exceeds limit of ") WFS _T("\n"),WF(m_nMaxInactiveTime),WF(m_ep.ActiveTimeout()));
1094 m_nTotalTime=Duration(Now()-m_tWallClock0);
1096 if(m_nTotalTime>m_ep.ElapsedTimeout()){
1097 Log(_T("\n*** Timeout - total time ") WFS _T(" exceeds limit of ") WFS _T("\n"), WF(m_nTotalTime),WF(m_ep.ElapsedTimeout()));
1102 SetStatus(m_bDownloading?DownloadTimeOut:TimeOut);
1108 // Convert a path to something a cygwin tool will understand. Used when invoking -size and -gdb
1109 String CeCosTest::CygPath (LPCTSTR pszPath)
1116 DWORD sz = sizeof(value);
1118 // look for the cygdrive prefix in the user's registry settings
1119 if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Cygnus Solutions\\Cygwin\\mounts v2", 0, KEY_READ, &hKey)) {
1120 if (ERROR_SUCCESS == RegQueryValueEx(hKey, "cygdrive prefix", NULL, & type, value, & sz)) {
1121 str = (const char*) value;
1126 // if not yet found, look for the cygdrive prefix in the system registry settings
1129 if (str.empty() && (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Cygnus Solutions\\Cygwin\\mounts v2", 0, KEY_READ, &hKey))) {
1130 if (ERROR_SUCCESS == RegQueryValueEx(hKey, "cygdrive prefix", NULL, & type, value, & sz)) {
1131 str = (const char*) value;
1136 int prefixlen = str.length();
1137 TCHAR *buf=str.GetBuffer(prefixlen+1+MAX_PATH);
1139 if(::GetFullPathName(pszPath,MAX_PATH,prefixlen+buf, &pszFname)){
1140 GetShortPathName(prefixlen+buf,prefixlen+buf,MAX_PATH); // ignore errors
1141 buf[prefixlen+1]=buf[prefixlen];
1142 buf[prefixlen]=_TCHAR('/');
1143 for(int i=prefixlen+2;buf[i];i++){
1144 if(_TCHAR('\\')==buf[i]){
1148 str.ReleaseBuffer();
1151 str.ReleaseBuffer();
1158 void CeCosTest::SetExecutable(LPCTSTR pszExecutable)
1162 m_strExecutable=pszExecutable;
1163 if(m_ep.Platform()){
1166 ERROR(_T("Don't know how to get sizes of this platform type\n"));
1169 m_strExecutable=_T("");
1173 // Calculate the sizes of the given file. The target parameter is necessary in order to
1174 // determine which -size executable to use to do the job.
1175 bool CeCosTest::GetSizes()
1177 TRACE(_T("GetSizes %s\n"),(LPCTSTR)Executable());
1179 m_nStrippedSize=m_nFileSize=0;
1180 LPCTSTR pszPrefix=m_ep.Platform()->Prefix();
1182 if(-1==_tstat(Executable(),&buf)){
1183 Log(_T("%s does not exist\n"),(LPCTSTR)Executable());
1184 } else if (_TCHAR('\0')==*pszPrefix){
1185 LogString(_T("No prefix to run a size program\n"));
1187 m_nFileSize=buf.st_size;
1188 const String strSizeCmd(String::SFormat(_T("%s-size %s"),pszPrefix,(LPCTSTR)CygPath(Executable())));
1191 if(!sp.Run(strOut,strSizeCmd)){
1192 Log(_T("Failed to run \"%s\" - %s\n"),(LPCTSTR)strSizeCmd,(LPCTSTR)sp.ErrorString());
1194 const TCHAR *c=_tcschr(strOut,_TCHAR('\n'));
1200 if(c && 2==_stscanf(c,_T(" %d %d"),&s1,&s2)){
1202 m_nStrippedSize=s1+s2;
1204 TRACE(_T("GetSizes %s rc=%d file size=%d stripped size=%d\n"),(LPCTSTR)Executable(),rc,m_nFileSize,m_nStrippedSize);
1210 void CeCosTest::SetTimeouts (Duration dActive,Duration dDownload/*,Duration dElapsed*/)
1212 m_ep.SetActiveTimeout (dActive);
1213 m_ep.SetDownloadTimeout(dDownload);
1215 m_ep.SetElapsedTimeout (dElapsed);
1219 void CeCosTest::CloseSocket (){
1224 bool CeCosTest::AtPrompt()
1226 const String strPrompt(m_ep.Platform()->Prompt());
1227 unsigned int nPromptLen=_tcslen(strPrompt);
1230 m_strOutput.size()>=nPromptLen &&
1231 0==_tcscmp((LPCTSTR)m_strOutput+m_strOutput.size()-nPromptLen,strPrompt);
1235 BOOL WINAPI HandlerRoutine(
1236 DWORD dwCtrlType // control signal type
1239 dwCtrlType; // eliminate compiler warning
1245 bool CeCosTest::InteractiveInferior(LPCTSTR pszHostPort,TCHAR **argv)
1248 if(_TCHAR('\0')!=*pszHostPort){
1249 if(!CeCosSocket::IsLegalHostPort(pszHostPort)){
1250 ERROR(_T("Illegal host:port '%s'\n"),pszHostPort);
1253 m_strExecutionHostPort=pszHostPort;
1254 Log(_T("Waiting to connect to %s...\n"),(LPCTSTR)m_strExecutionHostPort);
1257 Log(_T("Waiting to connect to a server...\n"));
1260 ConnectForExecution();
1262 Log(_T("Connected to %s - waiting for target reset\n"),(LPCTSTR)m_strExecutionHostPort);
1263 String strHostPort,strOutput;
1265 // target ready indicator
1266 // any output so far
1267 // (if target ready) host:port
1268 if(GetTargetReady(strHostPort)){
1269 Log(_T("Use target remote %s\n"),(LPCTSTR)strHostPort);
1270 String strInferior(m_ep.Platform()->Prefix());
1271 strInferior+=_T("-gdb");
1273 SetConsoleCtrlHandler(HandlerRoutine,TRUE);
1274 int n=_tspawnvp(_P_WAIT,strInferior,argv);
1276 Log(_T("Failed to spawn %s\n"),(LPCTSTR)strInferior);
1280 SetConsoleCtrlHandler(HandlerRoutine,FALSE);
1286 _ftprintf(stderr,_T("fork failed\n"));
1290 // Process is created (we're the child)
1291 execvp(strInferior,argv);
1292 Log(_T("Error invoking %s - %s\n"),(LPCTSTR)strInferior,strerror(errno));
1296 // Process is created (we're the parent)
1298 signal(SIGINT,SIG_IGN);
1300 waitpid(pid,&stat,0);
1302 signal(SIGINT,SIG_DFL);
1307 Log(_T("Inferior terminated\n"));
1308 // Tell the server we're through
1309 m_pSock->sendInteger(123,_T("Terminating ack"));
1314 void CALLBACK CeCosTest::ResetLogFunc(void *pParam, LPCTSTR psz)
1316 CeCosTest *pTest=(CeCosTest *)pParam;
1317 TRACE(_T("Send Target Ready indicator=2\n"));
1318 pTest->m_pSock->sendInteger(2,_T("target ready indicator"));
1319 TRACE(_T("Send %s\n"),psz);
1320 pTest->m_pSock->sendString(psz,_T("output so far"));
1323 CeCosTest::ExecutionParameters::RequestType CeCosTest::ExecutionParameters::RequestTypeValue(LPCTSTR psz)
1326 for(r=0;r<RequestTypeMax;r++){
1327 if(0==_tcsicmp(psz,arRequestImage[r])){
1331 return (RequestType)r;
1334 void CeCosTest::InferiorOutputFunc(LPCTSTR pszMsg)
1338 m_nOutputLen+=_tcslen(pszMsg);
1341 m_pspPipe->Send(pszMsg);
1344 if(m_nOutputLen>20000){
1345 LogString(_T("\n>>>> Infra FAIL\n*** too much output ***\n>>>>\n"));
1350 m_tBase=InferiorTime(); // We are seeing life, so reset the clock for timeouts
1354 // gdb's output included one or more prompts
1355 // Send another command along
1356 if(m_nCmdIndex>=m_arstrInferiorCmds.size()){
1357 // Nothing further to say to gdb - exit
1359 m_psp->Kill(); // case 3
1362 if(m_nCmdIndex>0 && 0==_tcscmp(_T("load"),m_arstrInferiorCmds[m_nCmdIndex-1])){
1363 // load command was previous command - we are no longer downloading
1364 m_bDownloading=false;
1367 String strCmd(m_arstrInferiorCmds[m_nCmdIndex++]);
1369 // If we can there is a GDB instruction to send to gdb, do it
1371 if(GetDirective(_T("GDB:"),str,m_nLastGdbInst)){
1373 m_nCmdIndex--; // undo increment above
1376 if(0==_tcscmp(_T("load"),strCmd)){
1377 // load command issued - we are now "downloading"
1378 m_bDownloading=true;
1379 } else if(0==_tcscmp(_T("run"),strCmd) || 0==_tcscmp(_T("cont"),strCmd)){
1380 SetStatus(NoResult);
1383 strCmd+=_TCHAR('\n');
1385 m_psp->Send(strCmd);
1390 // If there is a EXEC instruction to process, obey it
1392 while(GetDirective(_T("EXEC:"),strCmd,m_nLastExecInst)){
1393 CSubprocess *pExecsp=new CSubprocess;
1394 pExecsp->SetPath(m_strPath);
1395 if(!pExecsp->Run(AppendFunc,this,(LPCTSTR)strCmd,false)){
1396 Log(_T("%%%% Failed to create process '%s'\n"),(LPCTSTR)strCmd);
1399 m_arpExecsp.push_back(pExecsp);
1403 // If there is a PIPE instruction to process, obey it
1404 while(GetDirective(_T("PIPE:"),strCmd,m_nLastPipeInst)){
1406 Log(_T("%%%% Two PIPE commands are a no-no\n"));
1408 m_pspPipe=new CSubprocess;
1409 m_pspPipe->SetPath(m_strPath);
1411 if(!m_pspPipe->Run(AppendFunc,this,(LPCTSTR)strCmd,false)){
1412 Log(_T("%%%% Failed to create process '%s'\n"),(LPCTSTR)strCmd);
1416 // Send what we read have so far
1417 m_pspPipe->Send(m_strOutput);
1422 while(GetDirective(_T("TIMEOUT:"),strCmd,m_nLastTimeoutInst)){
1423 int n=_ttoi(strCmd);
1425 SetTimeouts(n); // second parameter is download timeout, which is now irrelevant
1427 Log(_T("%%%% Illegal timeout specified: %s\n"),(LPCTSTR)strCmd);
1432 void CeCosTest::RunInferior(LPCTSTR pszCmdline)
1434 m_psp=new CSubprocess;
1435 m_psp->SetContinuationFunc(SCheckForTimeout,this);
1437 m_nMaxInactiveTime=0;
1441 m_bDownloading=false;
1443 // Decide on the baseline status - NotStarted if there is a download element, NoResult otherwise.
1445 for(unsigned int i=0;i<m_arstrInferiorCmds.size();i++){
1446 if(0==_tcscmp(_T("run"),m_arstrInferiorCmds[i]) || 0==_tcscmp(_T("cont"),m_arstrInferiorCmds[i])){
1447 m_Status=NotStarted;
1451 TRACE(_T("Status <- %s\n"),(LPCTSTR)Image(m_Status));
1453 m_tPrevSample=0; // force an initial reading
1454 m_tInferiorCpuTime=0;
1456 m_tBase=m_tBase0=InferiorTime(); // Returns either Now() or nothing
1457 m_tWallClock0=Now();
1461 TRACE(_T("RunGDB()\n"));
1463 m_nLastGdbInst=m_nLastExecInst=m_nLastTimeoutInst=m_nLastPipeInst=0;
1464 m_psp->SetPath(m_strPath);
1465 if(m_psp->Run(SInferiorOutputFunc,this,pszCmdline,true)){
1468 m_pspPipe->Send(_T("\n"));
1469 m_pspPipe->CloseInput();
1470 if(m_pspPipe->Wait(5000)){
1471 // OK the pipe process terminated.
1472 int rc=m_pspPipe->GetExitCode();
1474 Log(_T("%%%% Pipe process returned rc=%d\n"),rc);
1478 LogString(_T("%%%% Pipe process would not complete\n"));
1485 Log(_T("Failed to run \"%s\" - %s\n"),pszCmdline,(LPCTSTR)m_psp->ErrorString());
1489 ERROR(_T("!!! Exception caught in RunInferior()\n"));
1491 delete m_psp; // will cause process to be killed as necessary and completion to be waited for
1493 for(int i=0;i<(signed)m_arpExecsp.size();i++){
1494 delete (CSubprocess *)m_arpExecsp[i]; // ditto
1496 m_arpExecsp.clear();
1497 TRACE(_T("Exiting RunInferior()\n"));
1500 void CeCosTest::AnalyzeOutput()
1502 // This test is pulled out to allow ser_filter to simulate a test failure
1503 if(OutputContains(_T("FAIL:"))){
1507 if(OutputContains(_T("EXIT:"))||OutputContains(_T("NOTAPPLICABLE:"))){
1508 static LPCTSTR arpszKeepAlive[]={_T("FAIL:"),_T("NOTAPPLICABLE:"), _T("PASS:")};
1509 static const StatusType arStatus[] ={Fail, Inapplicable, Pass};
1510 for(unsigned int i=0;i<sizeof arpszKeepAlive/sizeof arpszKeepAlive[0];i++){
1511 if(OutputContains(arpszKeepAlive[i])){
1512 TRACE(_T("DriveInferior: saw '%s'\n"),arpszKeepAlive[i]);
1513 SetStatus(arStatus[i]); // Do not break!
1518 // Certain output spells failure...
1519 if(OutputContains(_T("cyg_assert_fail ("))){
1520 SetStatus(AssertFail);
1522 static LPCTSTR arpszSignals[]={_T("SIGBUS"), _T("SIGSEGV"), _T("SIGILL"), _T("SIGFPE"), _T("SIGSYS"), _T("SIGTRAP")};
1523 for(unsigned int i=0;i<sizeof arpszSignals/sizeof arpszSignals[0];i++){
1525 str1.Format(_T("signal %s"),arpszSignals[i]);
1526 str2.Format(_T("handle %s nostop"),arpszSignals[i]);
1527 if(OutputContains(str1)&&!OutputContains(str2)){
1536 while(GetDirective(_T("EXPECT:"),str,nIndex)){
1537 // s1 is the pointer to the text following the expect - that to be tested
1538 LPCTSTR s1=(LPCTSTR)m_strOutput+nIndex;
1539 while (_istspace(*s1)){
1542 // whereas s2 is the pointer to the text in the expect string (what we are expecting)
1543 LPCTSTR s2=(LPCTSTR)str;
1546 Log(_T("EXPECT:<> failure - expected '%s' saw '%s'\n"),(LPCTSTR)str,(LPCTSTR)m_strOutput+nIndex);
1556 bool CeCosTest::ExecutionParameters::FromStr(LPCTSTR psz)
1558 String str1,str2,str3,str4,str5;
1559 int nUseFilter,nUnused2,nUnused3;
1560 int nLen=_tcslen(psz);
1561 _stscanf(psz,_T("%s %s %d %d %d %d %d %d %d %d %s %s %s"),
1562 str1.GetBuffer(1+nLen),
1563 str2.GetBuffer(1+nLen),
1565 &m_nDownloadTimeout,
1572 str3.GetBuffer(1+nLen),
1573 str4.GetBuffer(1+nLen),
1574 str5.GetBuffer(1+nLen)
1576 m_bUseFilter=(0!=nUseFilter);
1577 m_bUnused2=(0!=nUnused2);
1578 m_bUnused3=(0!=nUnused3);
1579 str1.ReleaseBuffer();
1580 str2.ReleaseBuffer();
1581 str3.ReleaseBuffer();
1582 str4.ReleaseBuffer();
1583 str5.ReleaseBuffer();
1586 for(r=0;r<RequestTypeMax;r++){
1587 if(0==_tcscmp(arRequestImage[r],str2)){
1591 m_Request=(RequestType)r;
1592 return CeCosTestPlatform::IsValid(m_Target);
1595 CeCosTest::ExecutionParameters::ExecutionParameters (RequestType r,
1597 Duration nActiveTimeout/*=NOTIMEOUT*/,
1598 Duration nDownloadTimeout/*=NOTIMEOUT*/):
1601 m_nActiveTimeout(nActiveTimeout),
1602 m_nDownloadTimeout(nDownloadTimeout),
1612 String CeCosTest::ExecutionParameters::Image() const
1615 str.Format(_T("%s %s %d %d %d %d %d %d %d %d"),(LPCTSTR)PlatformName(),(LPCTSTR)Image(Request()),
1616 ActiveTimeout(),DownloadTimeout(),
1626 bool CeCosTest::GetTargetReady(String &strHostPort)
1631 if(!m_pSock->recvInteger(nTargetReady,_T("Target ready"),120*1000)){
1632 Log(_T("Failed to read target ready indicator from server - %s\n"),(LPCTSTR)m_pSock->SocketErrString());
1635 switch(nTargetReady){
1637 LogString(_T("Failed to reset target"));
1640 if(m_pSock->recvString(strHostPort, _T("host:port"))){
1641 TRACE(_T("Instructed to use %s\n"),(LPCTSTR)strHostPort);
1644 Log(_T("Failed to read host:port - %s\n"),(LPCTSTR)m_pSock->SocketErrString());
1650 if(m_pSock->recvString(strOutput, _T("output"))){
1651 LogString(strOutput);
1653 Log(_T("Failed to read output\n"),(LPCTSTR)m_pSock->SocketErrString());
1659 } while(2==nTargetReady);
1664 CeCosTest::ServerStatus CeCosTest::ServerStatusValue(LPCTSTR psz)
1667 for(s=0;s<ServerStatusMax;s++){
1668 if(0==_tcsicmp(psz,arServerStatusImage[s])){
1672 return (ServerStatus)s;
1676 // Gets a directive from the test output (like EXEC:)
1677 bool CeCosTest::GetDirective(LPCTSTR pszDirective, String &str, int &nIndex)
1681 LPCTSTR pszOutput=(LPCTSTR)m_strOutput;
1682 LPCTSTR pc=_tcsstr(pszOutput+nIndex,pszDirective);
1685 pc+=_tcslen(pszDirective); // Now after the final character (':') of the directive
1686 if(_TCHAR('<')==*pc){
1690 // Extract the argument
1693 // Process escapes: FIXME more escapes?
1695 if(_TCHAR('\\')==c){
1704 pc--; // avoid grief
1711 } else if (_TCHAR('>')==c) {
1712 nIndex=pc+1-pszOutput;
1715 } else if (_TCHAR('\n')==c) {
1716 nIndex=pc+1-pszOutput;
1717 Log(_T("%%%% Unterminated directive: %s"),(LPCTSTR)str);
1729 void CeCosTest::GetInferiorCommands(StringArray &arstrInferiorCmds)
1731 arstrInferiorCmds.clear();
1733 // Construct commands for gdb. The commands may be found (semicolon-separated) in the target info:
1734 const String strInferiorCmds(m_ep.Platform()->GdbCmds());
1736 int nCmds=strInferiorCmds.Chop(ar,_TCHAR(';'),false);
1737 for(int i=0;i<nCmds;i++){
1738 // Into each command must be substituted:
1740 // Port (%p) This will be a serial port (e.g. COM1) or a socket connection (e.g.aloo:8000) depending on circumstances.
1741 // and escapes must be dealt with.
1743 for(const TCHAR *pc=ar[i];*pc;pc++){
1745 // Process escapes: FIXME more escapes?
1749 strCmd+=_TCHAR('\t');
1753 strCmd+=_TCHAR('\n');
1765 strCmd+=_TCHAR('%');
1769 if(0==m_pResource->Baud()){
1770 goto NextCmd; // Suppress output of this command if there is no baud rate to output
1772 strCmd+=String::SFormat(_T("%d"),m_pResource->Baud());
1776 if(_TCHAR('\0')==*(m_pResource->Serial())){
1777 goto NextCmd; // Suppress output of this command if there is no serial port
1779 strCmd+=m_pResource->Serial();
1793 arstrInferiorCmds.push_back(strCmd);