--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/testconns/statdesktop/desktop/source/lib/src/statengine.cpp Mon Oct 04 02:58:21 2010 +0300
@@ -0,0 +1,1580 @@
+/*
+* Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+
+
+
+#include "stdafx.h"
+#include "STATEngine.h"
+#include "STATCommon.h"
+#include "INI.h"
+
+#include <string>
+
+//----------------------------------------------------------------------------
+// Constructor
+CSTATEngine::CSTATEngine()
+: pImageVerify(NULL), pConverter(NULL), pComms(NULL), pDecoder(NULL), pLog(NULL),
+ minimumdelay(100), maximumdelay(30000), eStopProcessing(STAT_RUN), iCurrentCommand(0), bMultithreaded(false),
+ eConnectType(SymbianInvalid), pDeviceInfo(NULL), iDeviceCode(0), iMaxTimeLimit(STAT_MAXTIME), dataSocket(NULL), settingSocket(true), iTEFSharedData(NULL)
+{
+ memset(&szAddress, 0, sizeof(szAddress));
+ statIniFile.SetIniFileName(STAT_INI_NAME);
+}
+
+
+//----------------------------------------------------------------------------
+// Destructor
+CSTATEngine::~CSTATEngine()
+{
+ Release();
+}
+
+
+//----------------------------------------------------------------------------
+// Set things up
+int
+CSTATEngine::Initialise(const STATCONNECTTYPE eConnect, const char *pAddress)
+{
+ iDelay = minimumdelay;
+
+
+
+
+ // logging - should be the first to be created for all other classes that depend on it
+ pLog = new CSTATLogFile;
+ if (!pLog)
+ return E_OUTOFMEM;
+
+ int ret = SetScreenshotDefaultDirectory();
+ if (ret != ITS_OK)
+ return ret;
+
+ // image verification
+ pImageVerify = new CSTATImageVerify(pLog);
+ if (!pImageVerify)
+ return E_OUTOFMEM;
+
+ // bitmap conversion
+ pConverter = new CSTATDataFormatConverter(pLog);
+ if (!pConverter)
+ return E_OUTOFMEM;
+
+ // script decoder
+ pDecoder = new CSTATScriptDecoder(pLog);
+ if (!pDecoder)
+ return E_OUTOFMEM;
+
+ // communications
+ pComms = new STATComms();
+ if (!pComms)
+ return E_OUTOFMEM;
+ else
+ {
+ EnterCriticalSection(&CriticalSection);
+
+ ret = pComms->SetTransport(eConnect);
+ if (ret == ITS_OK)
+ {
+ ret = pComms->Initialise();
+
+ if (ret == ITS_OK)
+ ret = pComms->Connect(pAddress);
+
+ if (ret == ITS_OK)
+ {
+ strcpy(szAddress, pAddress); // save port in case of restart after error
+ eConnectType = eConnect;
+ }
+ }
+
+ LeaveCriticalSection(&CriticalSection);
+ }
+ return ret;
+}
+
+
+
+//----------------------------------------------------------------------------
+// Release resources
+int
+CSTATEngine::Release(void)
+{
+ if (pImageVerify)
+ {
+ delete pImageVerify;
+ pImageVerify = NULL;
+ }
+
+ if (pConverter)
+ {
+ delete pConverter;
+ pConverter = NULL;
+ }
+
+ if (pDecoder)
+ {
+ delete pDecoder;
+ pDecoder = NULL;
+ }
+
+ if (pDeviceInfo)
+ {
+ delete [] pDeviceInfo;
+ pDeviceInfo = NULL;
+ }
+
+ if (iTEFSharedData)
+ {
+ delete [] iTEFSharedData;
+ iTEFSharedData = NULL;
+ }
+
+ EnterCriticalSection(&CriticalSection);
+
+ if (pComms)
+ {
+ delete pComms;
+ pComms = NULL;
+ }
+
+ // release this one last in case other objects are using it...
+ if (pLog)
+ {
+ pLog->CloseLogFile();
+ delete pLog;
+ pLog = NULL;
+ }
+
+ LeaveCriticalSection(&CriticalSection);
+ return ITS_OK;
+}
+
+
+//----------------------------------------------------------------------------
+// Sets up log file
+int
+CSTATEngine::SetLogging(const CString& logfilename, const char* prefix, bool append, bool bMessages, bool bFile,
+ MessageReporter *const aMessageReporter)
+{
+ EnterCriticalSection(&CriticalSection);
+ //set default logging path
+ CString defaultDirectory=STAT_LOGFILEPATH_VALUE;
+ //read from inifile if entry exists
+ if(statIniFile.SectionExists(ST_TEST_KEY) )
+ {
+ CString setting;
+ setting.Empty();
+ setting=statIniFile.GetKeyValue(ST_LOGFILEPATH,ST_TEST_KEY);
+ if(!setting.IsEmpty())
+ defaultDirectory = setting;
+ }
+ int ret = pLog->CreateLogFile(logfilename,defaultDirectory, prefix, append, bMessages, bFile);
+
+ pLog->SetMessageReporter(aMessageReporter);
+
+ // in case our transport was initialised before logging was
+ // display the initialisation message if there is one
+ if (ret == LOG_FILE_OK)
+ Message(pComms->Error());
+
+ LeaveCriticalSection(&CriticalSection);
+ return ret;
+}
+
+
+//----------------------------------------------------------------------------
+// Sets up log file
+void
+CSTATEngine::SetCommandDelay(int iMillisecondDelay)
+{
+ iDelay = iMillisecondDelay;
+
+ // set some limits
+ if (iDelay < 100)
+ iDelay = minimumdelay;
+
+ if (iDelay > 30000)
+ iDelay = maximumdelay;
+}
+
+
+//----------------------------------------------------------------------------
+// Open, read and count the amount of commands on this script
+int
+CSTATEngine::GetCommandCount(CString file, int *pCount)
+{
+ EnterCriticalSection(&CriticalSection);
+
+ int ret = pDecoder->Initialise(file, true);
+ if (ret != ITS_OK)
+ ret = pDecoder->Initialise(file, false);
+
+ if (ret == ITS_OK)
+ {
+ CSTATScriptCommand *pSendCommand;
+ int iCount = 0;
+
+ // get a command from the script
+ while (pDecoder->GetNextCommand(&pSendCommand) && ret == ITS_OK)
+ {
+ iCount++;
+ if (pSendCommand->cCommandID == STAT_END)
+ break;
+ }
+
+ // set the count
+ if (ret == ITS_OK)
+ (*pCount) = iCount;
+ }
+
+ pDecoder->Release();
+
+ LeaveCriticalSection(&CriticalSection);
+ return ret;
+}
+
+
+//----------------------------------------------------------------------------
+// Open and read a script file's contents
+int
+CSTATEngine::OpenScriptFile(CString file, bool bIsFile)
+{
+ EnterCriticalSection(&CriticalSection);
+
+ int ret = pDecoder->Initialise(file, bIsFile);
+
+ LeaveCriticalSection(&CriticalSection);
+ return ret;
+}
+
+
+//----------------------------------------------------------------------------
+// Execute a script file
+int
+CSTATEngine::RunScript(ScriptProgressMonitor *const monitor)
+{
+ int ret = ITS_OK;
+ iCurrentCommand = 0;
+ eStopProcessing = STAT_RUN;
+ iDeviceCode = 0;
+
+ // anything smaller can cause problems and doesn't make sense anyway!
+ if (iMaxTimeLimit < 1000)
+ iMaxTimeLimit = 1000;
+
+ // pointers to our command structures
+ CSTATScriptCommand *pSendCommand;
+ CSTATScriptCommand *pRecvCommand;
+
+ char lastCommand = NULL;
+
+ receivedData.Empty( );
+
+
+
+ // get a command from the script
+ while (pDecoder->GetNextCommand(&pSendCommand) && ret == ITS_OK)
+ {
+ iCurrentCommand++;
+
+ if (StopProcessing())
+ {
+ pComms->Send(STAT_RESYNCID);
+ ret = E_USERCANCEL;
+ break;
+ }
+
+ if (lastCommand == STAT_REBOOT)
+ {
+ ret = ITS_OK;
+ break;
+ }
+
+ switch(pSendCommand->cCommandID)
+ {
+ case 'P':
+ Message(pSendCommand->Command());
+ Sleep(atol(pSendCommand->Command()));
+ break;
+ case '/':
+ Message(pSendCommand->Command());
+ break;
+ case '#':
+ {
+ Message(pSendCommand->Command());
+ cScreenshotDirectory = pSendCommand->Command();
+ if(cScreenshotDirectory.Right(1) != _T("\\"))
+ cScreenshotDirectory += _T("\\");
+ CreateAllDirectories(cScreenshotDirectory);
+ }
+ break;
+
+ default:
+ {
+
+ // send the command and retrieve a response
+ int iResyncErrors = 0;
+ while ((ret = SendCommand(pSendCommand, &pRecvCommand)) == E_RESYNCCOMMAND)
+ {
+ Sleep(STAT_RETRYDELAY);
+ iResyncErrors++;
+ if (iResyncErrors > STAT_MAXERRORS)
+ {
+ Message("Too many resync errors - stopping");
+ ret = E_COMMANDFAILED;
+ break;
+ }
+
+ }
+
+ if (ret == ITS_OK)
+ {
+ // perform special operations for these commands
+ switch(pSendCommand->cCommandID)
+ {
+ case 'D':
+ StoreData(pRecvCommand->Command(), pRecvCommand->Length(), pDeviceInfo);
+ AppendCommandToSTATLog("*** DEVICE INFORMATION ***", pRecvCommand->Command(), pRecvCommand->Length());
+ break;
+ case 'S':
+ {
+ // convert and save the data returned in the response
+ CString image = pSendCommand->Command();
+ ret = ConvertAndSaveScreeenshot(image, pRecvCommand->Command(), pRecvCommand->Length());
+
+ // imave verification
+ if (ret == ITS_OK)
+ {
+ if (pImageVerify->IsActive() && pConverter->bWriteToFile)
+ {
+ ret = pImageVerify->VerifyImage(image);
+ if (ret == VERIFICATION_PASS)
+ ret = ITS_OK;
+ }
+ }
+ break;
+ }
+
+ case 'T':
+ {
+
+ if(dataSocket==NULL)
+ {
+
+ // filename has been sent, now send the file itself
+ CSTATScriptCommand oSendCommand;
+ oSendCommand.cCommandID = pRecvCommand->cCommandID;
+
+ // read and send the file contents
+ if ((ret = ReadTransferFile(pSendCommand->Command(), &oSendCommand)) == ITS_OK)
+ {
+ int iResyncErrors = 0;
+ while ((ret = SendCommand(&oSendCommand, &pRecvCommand)) == E_RESYNCCOMMAND)
+ {
+ Sleep(STAT_RETRYDELAY);
+ iResyncErrors++;
+ if (iResyncErrors > STAT_MAXERRORS)
+ {
+ Message("Too many resync errors - stopping");
+ ret = E_COMMANDFAILED;
+ break;
+ }
+ }
+ }
+
+ }
+ else
+ {
+ //release the socket
+ ret = ReleaseSocket();
+
+ }
+
+
+ break;
+ }
+ case 'R':
+ case 'X':
+ {
+ if(dataSocket==NULL)
+ {
+ // save the file contents
+ ret = SaveTransferFile(pSendCommand->Command(), pRecvCommand->Command(), pRecvCommand->Length());
+ }
+ else
+ {
+ //release the socket
+ ret = ReleaseSocket();
+ }
+ break;
+ }
+ case 'G':
+ {
+ // upload the device log file and write to STAT log file
+ AppendCommandToSTATLog("*** DEVICE LOG ***", pRecvCommand->Command(), pRecvCommand->Length());
+ break;
+ }
+ case STAT_REFRESH:
+ case STAT_END:
+ {
+ ret = END_SCRIPT;
+ break;
+ }
+ case 'N':
+ {
+ // Retrieve the TEF shared data
+ StoreData(pRecvCommand->Command(), pRecvCommand->Length(), iTEFSharedData);
+ AppendCommandToSTATLog("*** RETRIEVE TEF SHARED DATA ***", pRecvCommand->Command(), pRecvCommand->Length());
+ }
+ break;
+ default:
+ {
+ Sleep(iDelay);
+ break;
+ }
+ }
+ }
+
+ if (ret == ITS_OK)
+ {
+ // Data received from certain of the commands is stored
+ // for retreival later.
+ switch(pSendCommand->cCommandID)
+ {
+ case 'W':
+ case 'V':
+ //execute returns pid
+ case 'J':
+ //poll returns 0 1
+ case '3':
+ receivedData += oRecvCommand.Command();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ }
+
+ lastCommand = pSendCommand->cCommandID;
+
+ if(monitor)
+ {
+ monitor->OnCompleteCommand( iCurrentCommand );
+ }
+ }
+
+ pDecoder->Release();
+
+ return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Converts a char * to it's Unicode equivalent
+//
+LPTSTR
+CSTATEngine::ToUnicode(const char *string)
+{
+#ifdef UNICODE
+ static TCHAR szBuffer[MAX_UNICODE_LEN + 1] = {0};
+ szBuffer[0] = (TCHAR)0;
+
+ // Convert to UNICODE.
+ if (!MultiByteToWideChar(CP_ACP, // conversion type
+ 0, // flags
+ string, // source
+ -1, // length
+ szBuffer, // dest
+ MAX_UNICODE_LEN)) // length
+ {
+ return _T("Could not convert");
+ }
+ return szBuffer;
+#else
+ return (LPTSTR)string;
+#endif
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Converts a Unicode to it's char * equivalent
+//
+char *
+CSTATEngine::ToAnsi(LPCTSTR string)
+{
+#ifdef UNICODE
+ static char szBuffer[MAX_UNICODE_LEN + 1] = {0};
+ szBuffer[0] = (char)0;
+
+ // Convert to ANSI.
+ if (!WideCharToMultiByte(CP_ACP, // conversion type
+ 0, // flags
+ string, // source
+ -1, // length
+ szBuffer, // dest
+ MAX_UNICODE_LEN, // length
+ NULL,
+ NULL ))
+ {
+ return "Could not convert";
+ }
+ return szBuffer;
+#else
+ return (char *)string;
+#endif
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// PRIVATE METHODS
+//////////////////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// sets screenshot image directory
+int CSTATEngine::SetScreenshotDefaultDirectory(void)
+{
+ //Set default logfile path
+ CString path = ST_LOGFILEPATH_VALUE;
+ //read from inifile if entry exists
+ if(statIniFile.SectionExists(ST_TEST_KEY) )
+ {
+ CString setting;
+ setting.Empty();
+ setting=statIniFile.GetKeyValue(ST_LOGFILEPATH,ST_TEST_KEY);
+ if(!setting.IsEmpty())
+ path = setting;
+ }
+
+
+ cScreenshotDirectory = path;
+
+ // add a backslash
+ if (cScreenshotDirectory.Right(1) != _T('\\'))
+ cScreenshotDirectory += _T('\\');
+
+ cScreenshotDirectory += _T("Images\\");
+
+ return ITS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+// Execute a complete command
+//
+// Sends a command, breaking it up into separate commands if required
+//
+// When sending, if larger than our buffer , break it up into correctly sized
+// pieces and send these. The first will be an empty one containing the total
+// size, followed by buffer-sized pieces. The last will be an empty command.
+//
+
+//////////////////////////////////////////////////////////////////////////////////////
+int CSTATEngine::SendCommand(CSTATScriptCommand *pSendCommand, CSTATScriptCommand **ppRecvCommand)
+{
+ int ret = GENERAL_FAILURE;
+ CSTATScriptCommand tempCommand;
+ tempCommand.cCommandID = pSendCommand->cCommandID;
+
+
+ // the first instance of a 'R' or 'T' command, it could set a data socket instead of a file
+ if(pSendCommand->cCommandID=='T' || pSendCommand->cCommandID=='R')
+ {
+ if(dataSocket==NULL && settingSocket && pSendCommand->Command()!=NULL)
+ {
+
+ char *comma = strchr(pSendCommand->Command(),',');
+
+ if(!(comma > pSendCommand->Command() + pSendCommand->Length()))
+ {
+
+ switch(pSendCommand->cCommandID)
+ {
+ case 'R':
+ {
+ char *colon = strchr(comma,':');
+
+ if(colon==NULL)
+ break;
+
+ comma += 1;
+ std::string ipAdd( comma, colon - comma );
+ colon += 1;
+ std::string ipPort( colon );
+
+ ret = SetSocket(ipAdd.c_str() , atoi( ipPort.c_str() ));
+
+ if(ret!=ITS_OK)
+ {
+ return ret;
+ }
+
+ break;
+ }
+
+ case 'T':
+ {
+ char *colon = strchr( pSendCommand->Command() , ':' );
+
+ if(colon==NULL)
+ break;
+
+ std::string ipAdd( pSendCommand->Command() , colon - pSendCommand->Command() );
+ colon += 1;
+
+ if(comma < colon)
+ break;
+
+ std::string ipPort( colon , comma - colon );
+
+ ret = SetSocket(ipAdd.c_str() , atoi(ipPort.c_str()));
+
+ if(ret!=ITS_OK)
+ {
+ return ret;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ settingSocket=false;
+ }
+
+
+
+ // send the first command
+ if ((ret = SendSingleCommand(pSendCommand, ppRecvCommand)) == ITS_OK)
+ {
+ // check our response - if Serial/Infra-red, need to break it down
+ if (pComms->GetMaxPacketSize() != 0)
+ {
+
+
+ // break up the command into buffer-sized chunks
+ if (pSendCommand->Length() > pComms->GetMaxPacketSize() || (dataSocket!=NULL && pSendCommand->cCommandID=='T'))
+ {
+ int i = 0;
+ unsigned long offset = 0;
+ unsigned long ulTotalWritten = 0;
+ unsigned long AmountToWrite = pComms->GetMaxPacketSize();
+ unsigned long OriginalLength = pSendCommand->Length();
+
+ if(dataSocket==NULL)
+ {
+
+ int iWrites = pSendCommand->Length() / pComms->GetMaxPacketSize() + 1;
+
+ Message("Writing %d bytes of data in %d separate writes...", OriginalLength, iWrites);
+ for (i=0;i<iWrites;i++)
+ {
+ offset = i * pComms->GetMaxPacketSize();
+
+ if ((pSendCommand->Length() - offset) < pComms->GetMaxPacketSize())
+ AmountToWrite = (pSendCommand->Length() - offset);
+
+ if (AmountToWrite)
+ {
+ //Sleep(100); // pause a bit for slower machines - probably doesn't need it but it can't hurt...
+
+ // now send the command
+ Message("Writing %d bytes from offset %d", AmountToWrite, offset);
+ tempCommand.SetData(pSendCommand->Command() + ulTotalWritten, AmountToWrite);
+ if ((ret = SendSingleCommand(&tempCommand, ppRecvCommand)) == ITS_OK)
+ {
+ //Message("%d bytes successfully written", AmountToWrite);
+ }
+ else
+ return ret;
+
+ ulTotalWritten += AmountToWrite;
+ }
+ }
+
+ }
+ else
+ {
+
+ //uses socket transmission
+
+ char *pData = new char[AmountToWrite];
+
+ tempCommand.ulLength = (unsigned long) -1;
+
+ if((ret = SendSingleCommand(&tempCommand, ppRecvCommand)) != ITS_OK)
+ {
+ delete [] pData;
+ return ret;
+ }
+
+ while(true){
+
+
+ int AmountToWrite = pComms->GetMaxPacketSize();
+
+ ReadFromSocket(pData, &AmountToWrite );
+
+ if(AmountToWrite>=0)
+ {
+ Message("Writing %d bytes", AmountToWrite);
+ tempCommand.SetData(pData , AmountToWrite);
+
+ if ((ret = SendSingleCommand(&tempCommand, ppRecvCommand)) == ITS_OK)
+ {
+ //Message("%d bytes successfully written", AmountToWrite);
+ }
+ else
+ {
+ settingSocket=true;
+ delete [] pData;
+ return ret;
+ }
+
+ ulTotalWritten +=AmountToWrite;
+ }
+ else
+ {
+ eStopProcessing = STAT_PAUSE;
+ break;
+ }
+
+ if(AmountToWrite==0)
+ {
+ break;
+ }
+
+ }
+
+ delete [] pData;
+
+ }
+
+ // once completely sent, send an empty command to show that we've finished
+
+
+ if(dataSocket == NULL )
+ {
+ if (ulTotalWritten == OriginalLength)
+ {
+ // send the command that signals the end of our transmission
+ Message("Sending completion command %c", tempCommand.cCommandID);
+ tempCommand.SetData(NULL, 0);
+ if ((ret = SendSingleCommand(&tempCommand, ppRecvCommand)) == ITS_OK)
+ {
+ //Message("Completion command successfully written");
+ }
+ }
+ else
+ {
+ Message("Incorrect number of bytes written - expected %ld got %ld", ulTotalWritten, OriginalLength);
+ ret = E_BADNUMBERBYTES;
+ }
+ }
+ }
+ }
+ }
+
+ if (ret == ITS_OK)
+ {
+ // check our response - if Serial/Infra-red, need to break it down
+ // if < STAT_BUFFERSIZE, nothing more to do
+ // if not, we need to read in as many times as it takes to
+ // assemble our complete command response
+ if (pComms->GetMaxPacketSize() != 0)
+ {
+ if (ppRecvCommand && (*ppRecvCommand)->Length() > pComms->GetMaxPacketSize())
+ {
+ unsigned long TotalLength = (*ppRecvCommand)->Length();
+
+ Message("%s: About to read %d bytes of data", GetConnection(eConnectType), TotalLength);
+
+ // allocate memory to hold entire command
+ char *pTemp = new char [TotalLength];
+ if (pTemp)
+ {
+ unsigned long ulTotalRead = 0;
+
+ // empty packets
+ tempCommand.SetData(NULL, 0);
+
+ // now read data until we get an empty packet
+ while((*ppRecvCommand)->Length())
+ {
+ //Sleep(100); // pause a bit for slower machines - probably doesn't need it but it can't hurt...
+
+ //Message("Sending continuation command %c", tempCommand.cCommandID);
+ if ((ret = SendSingleCommand(&tempCommand, ppRecvCommand)) == ITS_OK)
+ {
+ if ((*ppRecvCommand)->Length())
+ {
+ Message("%s to offset %d", pComms->Error(), ulTotalRead);
+
+ //copy the data into the buffer
+ memcpy(pTemp + ulTotalRead, (*ppRecvCommand)->Command(), (*ppRecvCommand)->Length());
+
+ if(dataSocket!=NULL)
+ {
+ int bytesSent = (int)(*ppRecvCommand)->Length();
+
+ WriteToSocket((*ppRecvCommand)->Command() , &bytesSent);
+
+ if(bytesSent <= 0)
+ {
+ eStopProcessing = STAT_PAUSE;
+ }
+ }
+
+
+
+ //increment the pointer to the end of the first chunk received
+ ulTotalRead += (*ppRecvCommand)->Length();
+ }
+ }
+ else
+ {
+ settingSocket=true;
+ delete [] pTemp;
+ return ret;
+ }
+ }
+
+ // make sure we got what we expected
+ if (ulTotalRead == TotalLength)
+ {
+ // set our final response to the complete data transmission
+ (*ppRecvCommand)->SetData(pTemp, ulTotalRead);
+ //Message("Received successfully %ld bytes", ulTotalRead);
+ }
+ else
+ {
+ Message("Incorrect number of bytes read - expected %ld got %ld", ulTotalRead, TotalLength);
+ ret = E_BADNUMBERBYTES;
+ }
+
+ // finished with it
+ delete [] pTemp;
+ }
+ else
+ {
+ Message("Could not allocate %d bytes of memory", TotalLength);
+ ret = E_OUTOFMEM;
+ }
+ }
+ else if(dataSocket!=NULL && pSendCommand->cCommandID=='R')
+ {
+ int bytesSent = (int)(*ppRecvCommand)->Length();
+ WriteToSocket((*ppRecvCommand)->Command(), &bytesSent);
+ }
+ }
+ }
+
+
+
+ return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+// Execute a single command
+//
+// Once the command is sent, wait for a response. If received and of the correct
+// ID, save the contents (if any) and quit. If no response, send RESYNC commands
+// every few seconds to get response from other end. On receipt of a RESYNC
+// command, resend the previous command. After no response for a minute or so, quit.
+//////////////////////////////////////////////////////////////////////////////////////
+int CSTATEngine::SendSingleCommand(CSTATScriptCommand *pSendCommand, CSTATScriptCommand **ppRecvCommand)
+{
+ int iTotalCommandTime = 0;
+ int ret = GENERAL_FAILURE;
+
+ LogDetails("Send", pSendCommand);
+
+ // send the command
+ EnterCriticalSection(&CriticalSection);
+ ret = pComms->Send(pSendCommand->cCommandID, pSendCommand->Command(), pSendCommand->Length());
+ LeaveCriticalSection(&CriticalSection);
+ if (ret != ITS_OK)
+ {
+ Message(pComms->Error());
+ return ret;
+ }
+
+ // The refresh command will not return anything due to the transport getting restarted.
+ // So, don't wait for a response.
+ if( (ret == ITS_OK) && (pSendCommand->cCommandID == STAT_REFRESH || pSendCommand->cCommandID == STAT_REBOOT) )
+ {
+ return ret;
+ }
+
+ // wait for a response
+ unsigned long ulLength = 0;
+ char *pData = NULL;
+ while(iTotalCommandTime < iMaxTimeLimit)
+ {
+ if (StopProcessing())
+ {
+ pComms->Send(STAT_RESYNCID);
+ ret = E_USERCANCEL;
+ break;
+ }
+
+ EnterCriticalSection(&CriticalSection);
+ ret = pComms->Receive(&oRecvCommand.cCommandID, &pData, &ulLength);
+ LeaveCriticalSection(&CriticalSection);
+
+ if (ret == ITS_OK)
+ {
+ if (oRecvCommand.SetData(pData, ulLength))
+ {
+ oRecvCommand.ulLength = ulLength;
+ *ppRecvCommand = &oRecvCommand;
+
+ // invalid response received
+ if (pSendCommand->cCommandID != oRecvCommand.cCommandID)
+ {
+ // need to resync back to start of this command
+ if (oRecvCommand.cCommandID == STAT_RESYNCID)
+ {
+ Message("RESYNC response received - retrying command...");
+ ret = E_RESYNCCOMMAND;
+ }
+ else
+ {
+ if (oRecvCommand.cCommandID == STAT_FAILURE)
+ {
+ if (oRecvCommand.Command() && oRecvCommand.Length())
+ {
+ Message("Command failed with error code %s",
+ oRecvCommand.Command());
+ iDeviceCode = atoi(oRecvCommand.Command());
+ }
+ }
+ else
+ Message("Invalid response received - expected %c received %c",
+ pSendCommand->cCommandID, oRecvCommand.cCommandID);
+ ret = GENERAL_FAILURE;
+ }
+ }
+ else
+ LogDetails("Receive", *ppRecvCommand);
+ }
+ else
+ ret = E_OUTOFMEM;
+
+ // at this point we have received something whether it's what we were expecting or not so exit loop
+ break;
+ }
+ else if (ret == NO_DATA_AT_PORT)
+ {
+// Message("Waiting for response");
+ Sleep(STAT_RETRYDELAY);
+ iTotalCommandTime += STAT_RETRYDELAY;
+ ret = E_TOOMUCHTIME;
+ }
+ else
+ {
+ Message(pComms->Error());
+ break;
+ }
+ }
+
+ return ret;
+}
+
+
+//----------------------------------------------------------------------------
+// Write command details to log
+void CSTATEngine::LogDetails(const char *prefix, CSTATScriptCommand *pCommand)
+{
+ if (pCommand->Length() && (pCommand->Length() < MAX_LOG_MSG_LEN) &&
+ pCommand->cCommandID != 'D' && pCommand->cCommandID != 'T' && pCommand->cCommandID != 'R' && pCommand->cCommandID != 'X' && pCommand->cCommandID != 'G')
+ {
+ char szContents[MAX_LOG_MSG_LEN + 1];
+ unsigned long actuallen = MAX_LOG_MSG_LEN - 30 - strlen(prefix) - 6; // max actual message length
+ if (pCommand->Length() < actuallen)
+ actuallen = pCommand->Length();
+
+ strncpy(szContents, pCommand->Command(), actuallen);
+ *(szContents + actuallen) = (char)0;
+ Message("%s: ID: %c Contents: [%s] Length: [%lu]", prefix, pCommand->cCommandID, szContents, pCommand->Length());
+ }
+ else
+ Message("%s: ID: %c Length: [%lu]", prefix, pCommand->cCommandID, pCommand->Length());
+}
+
+
+//----------------------------------------------------------------------------
+// Read in a file's contents
+//
+// pFile will contain "pc path,device path" of which we want the 'pc path' part
+int CSTATEngine::ReadTransferFile(const char *pFile, CSTATScriptCommand *pCommand)
+{
+ int ret = E_BADFILENAME;
+
+ // get the default file location
+ CString path = ST_WORKINGPATH_VALUE;
+ //read from inifile if entry exists
+ if(statIniFile.SectionExists(ST_TEST_KEY) )
+ {
+ CString setting;
+ setting.Empty();
+ setting=statIniFile.GetKeyValue(ST_WORKINGPATH,ST_TEST_KEY);
+ if(!setting.IsEmpty())
+ path = setting;
+ }
+
+ // add a backslash
+ if (path.Right(1) != _T('\\'))
+ path += _T('\\');
+
+ // get the name of the file
+ CString filename = pFile;
+ int index = filename.ReverseFind(_T(','));
+ if (index == -1)
+ return E_BADFILENAME;
+
+ // add the name
+ path += filename.Left(index);
+
+ Message("Opening file [%s]", ToAnsi(path));
+
+ EnterCriticalSection(&CriticalSection);
+
+ CFile script_file;
+ if (script_file.Open(path, CFile::modeRead))
+ {
+ try
+ {
+ char *pData = new char [script_file.GetLength()];
+ if (pData)
+ {
+ script_file.Read(pData, script_file.GetLength());
+
+ if(pCommand->SetData(pData, script_file.GetLength()))
+ ret = ITS_OK;
+ else
+ ret = E_OUTOFMEM;
+
+ delete [] pData;
+ }
+ else
+ ret = E_OUTOFMEM;
+ }
+ catch(CFileException *e)
+ {
+ e->Delete();
+ ret = GENERAL_FAILURE;
+ }
+
+ script_file.Abort();
+ }
+
+ LeaveCriticalSection(&CriticalSection);
+ return ret;
+}
+
+
+
+
+
+
+
+//----------------------------------------------------------------------------
+// Save a data stream to file
+//
+// pFile will contain "device path,pc folder" of which we want the 'pc folder' part
+int CSTATEngine::SaveTransferFile(const char *pFile, char *pContents, unsigned long ulLength)
+{
+ int ret = E_BADFILENAME;
+
+ CString path = ST_WORKINGPATH_VALUE;
+ //read from inifile if entry exists
+ if(statIniFile.SectionExists(ST_TEST_KEY) )
+ {
+ CString setting;
+ setting.Empty();
+ setting=statIniFile.GetKeyValue(ST_WORKINGPATH,ST_TEST_KEY);
+ if(!setting.IsEmpty())
+ path = setting;
+ }
+ // add a backslash
+ if (path.Right(1) != _T('\\'))
+ path += _T('\\');
+
+ // get any additional sub folders
+ CString folder = pFile;
+ int index = folder.Find(_T(','));
+ if (index == -1)
+ return E_BADFILENAME;
+ // if the comma is the last char there are no folders to add
+ if (folder.Right(1) != _T(','))
+ {
+ path += folder.Mid(index + 1);
+
+ // add a backslash
+ if (path.Right(1) != _T('\\'))
+ path += _T('\\');
+ }
+
+ if (bMultithreaded)
+ {
+ // add a sub-folder for the connection type
+ path += GetConnection(eConnectType);
+ path += _T(".");
+ path += szAddress;
+ path += _T('\\');
+ }
+
+ // now extract the filename from the first argument
+ CString filename = folder.Left(index);
+ index = filename.ReverseFind(_T('\\'));
+ if (index == -1)
+ path += filename;
+ else
+ path += filename.Mid(index + 1);
+
+ Message("Saving file [%s]", ToAnsi(path));
+
+ ret = SaveTheFile(path, pContents, ulLength);
+ if (ret != ITS_OK)
+ Message("Error saving [%s] (%d)", ToAnsi(path), GetLastError());
+ return ret;
+}
+
+
+//----------------------------------------------------------------------------
+// Convert and save a screenshot
+int CSTATEngine::ConvertAndSaveScreeenshot(CString &file, const char *pContents, const unsigned long ulLength)
+{
+ int ret = E_BADFILENAME;
+
+ // clean out any previous mbm files lying around
+ if (!RemoveLeftoverMBMFiles())
+ return E_SCREENSHOT_LEFTOVERFILES;
+
+ // get the destination screenshot name
+ CString destfile = file;
+ if (destfile.IsEmpty())
+ {
+ // construct a filename from date/time
+ char szName[20] = {0};
+ time_t curTime;
+ time (&curTime);
+ strftime (szName,
+ sizeof (szName),
+ "%Y%m%d%H%M%S",
+ localtime (&curTime));
+
+ destfile = szName;
+ }
+
+ // get the full name of the source image
+ CString SrcPath = cScreenshotDirectory;
+
+ if (bMultithreaded)
+ {
+ // add a sub-folder for the connection type
+ SrcPath += GetConnection(eConnectType);
+ SrcPath += _T(".");
+ SrcPath += szAddress;
+ SrcPath += _T('\\');
+ }
+
+ // attach the filename
+ CString path = SrcPath;
+
+ path += destfile;
+ path += _T(".mbm");
+
+// Message("Saving screenshot [%s]", ToAnsi(path));
+
+ // save bitmap data to file
+ if ((ret = SaveTheFile(path, pContents, ulLength)) == ITS_OK)
+ ret = pConverter->ConvertScreenShot(SrcPath, SrcPath);
+
+ // save the full path to the converted image
+ if (ret == ITS_OK)
+ file = SrcPath;
+ return ret;
+}
+
+
+//----------------------------------------------------------------------------
+// Save data to file
+int CSTATEngine::SaveTheFile(CString path, const char *pContents, const unsigned long ulLength)
+{
+ int ret = E_BADFILENAME;
+
+ EnterCriticalSection(&CriticalSection);
+
+ // ensure the path exists
+ CreateAllDirectories(path);
+
+ DeleteFile(path);
+
+ CFile script_file;
+ if (script_file.Open(path, CFile::modeCreate | CFile::modeWrite | CFile::shareDenyWrite))
+ {
+ try
+ {
+ // might be a zero-length file
+ if (pContents && ulLength)
+ script_file.Write(pContents, ulLength);
+
+ ret = ITS_OK;
+ }
+ catch(CFileException *e)
+ {
+ e->Delete();
+ ret = GENERAL_FAILURE;
+ }
+
+ script_file.Abort();
+ }
+
+ LeaveCriticalSection(&CriticalSection);
+ return ret;
+}
+
+
+//----------------------------------------------------------------------------
+// Write a message to the log
+void CSTATEngine::Message(const char *pMsg, ...)
+{
+ char szMessage[MAX_LOG_MSG_LEN + 1];
+
+ if (pMsg)
+ {
+ memset(&szMessage, 0, sizeof(szMessage));
+ va_list pCurrent = (va_list)0;
+ va_start (pCurrent, pMsg);
+ vsprintf (szMessage, pMsg, pCurrent);
+ va_end (pCurrent);
+ }
+ else
+ strcpy(szMessage, "No message associated with this error");
+
+ EnterCriticalSection(&CriticalSection);
+ pLog->Set(szMessage);
+ LeaveCriticalSection(&CriticalSection);
+}
+
+//----------------------------------------------------------------------------
+// Try to create all directories within a supplied path
+void CSTATEngine::CreateAllDirectories(CString &fullpath)
+{
+ CString path;
+ int index = fullpath.Find(_T('\\'));
+ while (index != -1)
+ {
+ path = fullpath.Left(index);
+ CreateDirectory(path, NULL);
+
+ index = fullpath.Find(_T('\\'), index + 1);
+ }
+}
+
+//----------------------------------------------------------------------------
+// check if we want to quit
+bool CSTATEngine::StopProcessing()
+{
+ // check if instructed to stop processing (will only happen on Desktop version)
+ if (eStopProcessing == STAT_PAUSE)
+ {
+ eStopProcessing = STAT_STOP;
+ return true;
+ }
+
+ return false;
+}
+
+//----------------------------------------------------------------------------
+//Remove any leftover .mbm files prior to retrieving a screenshot
+bool CSTATEngine::RemoveLeftoverMBMFiles()
+{
+ CFileFind imagefinder;
+ CString imagedir = cScreenshotDirectory;
+ bool valid = true;
+
+ // add the search pattern
+ if (imagedir.Right(1) != _T('\\'))
+ imagedir += _T("\\");
+
+ // now add a folder for the connection type
+ if (bMultithreaded)
+ {
+ imagedir += GetConnection(eConnectType);
+ imagedir += _T(".");
+ imagedir += szAddress;
+ imagedir += _T('\\');
+ }
+
+ imagedir += _T("*.mbm");
+
+// Message("Searching for [%s]", ToAnsi(imagedir));
+
+ EnterCriticalSection(&CriticalSection);
+
+ // locate files
+ int iLeftFiles = imagefinder.FindFile(imagedir, 0);
+ while (iLeftFiles)
+ {
+ iLeftFiles = imagefinder.FindNextFile();
+// Message("Deleting file [%s]", ToAnsi(imagefinder.GetFilePath()));
+
+ if (!DeleteFile(imagefinder.GetFilePath()))
+ {
+ valid = false;
+ break;
+ }
+ }
+
+ imagefinder.Close();
+ LeaveCriticalSection(&CriticalSection);
+ return valid;
+}
+
+
+//----------------------------------------------------------------------------
+// Append the device log to the end of the STAT log
+void CSTATEngine::AppendCommandToSTATLog(char *heading, char *log, unsigned long length)
+{
+ if (length && log)
+ {
+ EnterCriticalSection(&CriticalSection);
+ Message(DOTTED_LINE);
+ Message(heading);
+
+ char *start = log;
+ char *eol = log;
+ unsigned long count = 0;
+
+ *(log + length) = (char)0;
+
+ while (count < length - 1)
+ {
+ // find the end of the line
+ while ((count < length - 1) && (*eol != '\r') && (*eol != '\n'))
+ {
+ count++;
+ eol++;
+ }
+
+ // null it
+ if (count < length - 1)
+ {
+ *eol = (char)0;
+ count++;
+ eol++;
+ }
+
+ if (start && *start)
+ Message("%s", start);
+
+ // step over newline
+ while ((count < length - 1) && (*eol == '\r') || (*eol == '\n'))
+ {
+ count++;
+ eol++;
+ }
+
+ if (count < length - 1)
+ start = eol;
+ }
+
+ Message(DOTTED_LINE);
+ LeaveCriticalSection(&CriticalSection);
+ }
+ else
+ Message("No information returned from device");
+}
+
+//----------------------------------------------------------------------------
+// Store some data in a public defined char* pointer
+// (currently iTEFSharedData and pDeviceInfo)
+void CSTATEngine::StoreData( char* aData, unsigned long aLength, char*& aOutputPtr )
+{
+
+ receivedData.Empty();
+ receivedData = aData;
+
+ if( aOutputPtr )
+ {
+ delete [] aOutputPtr;
+ aOutputPtr = NULL;
+ }
+
+ if( aData && aLength )
+ {
+ aOutputPtr = new char[aLength + 1];
+ if( aOutputPtr )
+ {
+ // skip over leading CR/LF's
+ char *p = aData;
+ while (p && (*p) && (*p == '\r') || (*p == '\n'))
+ p++;
+ strcpy(aOutputPtr, p);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+// Translate a connection type to a string
+CString CSTATEngine::GetConnection(STATCONNECTTYPE eConnectType)
+{
+ CString connection;
+
+ switch(eConnectType)
+ {
+ case SymbianSocket:
+ connection = _T("SymbianSocket");
+ break;
+ case SymbianSerial:
+ connection = _T("SymbianSerial");
+ break;
+ case SymbianInfrared:
+ connection = _T("SymbianInfrared");
+ break;
+ case SymbianBluetooth:
+ connection = _T("SymbianBluetooth");
+ break;
+ case SymbianUsb:
+ connection = _T("SymbianUsb");
+ break;
+ default:
+ connection = _T("SymbianInvalid");
+ break;
+ };
+
+ return connection;
+}
+
+
+//----------------------------------------------------------------------------
+// Sets a data socket to read/write file streams
+//
+int CSTATEngine::SetSocket(const char *ip, const int port)
+{
+
+ //initialise winsock
+ WSAStartup( MAKEWORD(2,2), &wsaData );
+
+ dataSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
+
+ if ( dataSocket == INVALID_SOCKET )
+ {
+ dataSocket=NULL;
+ return E_SOCKETCREATE;
+ }
+
+ // Connect to a server.
+ sockaddr_in clientService;
+
+ clientService.sin_family = AF_INET;
+ clientService.sin_addr.s_addr = inet_addr( ip );
+ clientService.sin_port = htons( port );
+
+ if ( connect( dataSocket, (SOCKADDR*) &clientService, sizeof(clientService) ) == SOCKET_ERROR)
+ {
+ ReleaseSocket();
+ return E_SOCKETCONNECT;
+ }
+ else
+ {
+ return ITS_OK;
+ }
+
+
+
+}
+
+int CSTATEngine::ReleaseSocket()
+{
+ int ret = ITS_OK;
+
+ //release the socket
+ if( closesocket(dataSocket) == SOCKET_ERROR)
+ {
+ ret = E_SOCKETCLOSE;
+ }
+
+
+ //cleanup winsock
+ WSACleanup();
+
+ dataSocket=NULL;
+
+ return ret;
+
+}
+
+
+//----------------------------------------------------------------------------
+// Read from the board and write to the data socket
+//
+
+void CSTATEngine::WriteToSocket(const char *data, int *length)
+{
+ // Send data.
+ *length = send( dataSocket, data, *length , 0 );
+}
+
+
+
+//----------------------------------------------------------------------------
+// Read from the data socket and send to the board
+//
+void CSTATEngine::ReadFromSocket(char *data, int *length)
+{
+ int bufferSize = 0xFF;
+
+ if(*length >= bufferSize)
+ {
+
+ int packetLength = *length;
+
+ int totalRead = 0;
+ int iterRead = 0;
+
+ // Receive data to fill a packet
+ while(totalRead <= packetLength - bufferSize)
+ {
+ iterRead = recv( dataSocket, data + totalRead, bufferSize, 0 );
+ if(iterRead == 0)
+ break;
+ totalRead += iterRead;
+ }
+
+ *length = totalRead;
+ }
+ else
+ {
+ *length = recv( dataSocket, data, *length, 0 );
+ }
+}
+
+
+
+
+
+
+
+
+