diff -r 73b88125830c -r b8d1455fddc0 testconns/statdesktop/desktop/source/lib/src/statengine.cpp --- /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 + +//---------------------------------------------------------------------------- +// 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;iGetMaxPacketSize(); + + 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 ); + } +} + + + + + + + + +