Blame | Last modification | View Log | RSS feed
//---------------------------------------------------------------------------#include <vcl.h>#pragma hdrstop#include "DeviceSimulatorThread.h"#include "IDeviceFactory.h"#pragma package(smart_init)//---------------------------------------------------------------------------// Important: Methods and properties of objects in VCL can only be// used in a method called using Synchronize, for example://// Synchronize(UpdateCaption);//// where UpdateCaption could look like://// void __fastcall DeviceSimulatorThread::UpdateCaption()// {// Form1->Caption = "Updated in a thread";// }//---------------------------------------------------------------------------using namespace std;__fastcall DeviceSimulatorThread::DeviceSimulatorThread( IDevice * device,IDeviceFactory * factory,const AnsiString & hostname ) :TThread( false ),m_device( device ),m_factory( factory ),m_address( hostname ),m_running( false ),m_error( "" ){m_device->registerListener( this );SECURITY_ATTRIBUTES attribs = { 0 };attribs.nLength = sizeof( attribs );attribs.bInheritHandle = false;m_semaphore = CreateSemaphore( &attribs, 0, 10000, "DeviceSimulatorSemaphore" );}//---------------------------------------------------------------------------void DeviceSimulatorThread::SetName(){THREADNAME_INFO info;info.dwType = 0x1000;info.szName = "DeviceSimulatorThread";info.dwThreadID = -1;info.dwFlags = 0;__try{RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD),(DWORD*)&info );}__except (EXCEPTION_CONTINUE_EXECUTION){}}//---------------------------------------------------------------------------void __fastcall DeviceSimulatorThread::Execute(){SetName();m_running = true;try{// Connect the deviceif( !m_device->connect( m_address.c_str() ) ){m_error = "Device failed to connect to Site Computer at " + m_address + ":5003";}// Loop until exit, or an error has occuredwhile( m_running && m_error.IsEmpty() ){// Wait for:// 1. A disconnection/connection event to reconnect or update our status// 2. A request to upload a UD file from our manager// 3. A termination requestif( WaitForSingleObject( m_semaphore, INFINITE ) == WAIT_OBJECT_0 ){// Check connection stateif( !m_device->isConnected() ){Reconnect();}// Perform any transfers requiredTransferUdFiles();ReleaseSemaphore( m_semaphore, 1, NULL );}}}__finally{// Terminate and cleanup. Destroy the device using the factory or// exceptions will be raised.m_device->detachListener( this );m_device->disconnect();m_running = false;m_factory->destroyDevice( *m_device );m_device = 0;CloseHandle( m_semaphore );}}//---------------------------------------------------------------------------void DeviceSimulatorThread::Reconnect(){//TODO: configurable?const int retries = 5;if( !m_device->isConnected() ){bool connected = false;int connectCount = retries;while( (connectCount >= 0) && !connected ){m_device->connect( m_address.c_str() );connectCount--;int checkCount = retries;while( (checkCount >= 0) && !(connected = m_device->isConnected()) ){checkCount--;Sleep( 500 );}}// Terminate if we couldn't get a connectionif( !connected ){m_error.sprintf( "Failed to connect to site computer %s", m_address );}}}//---------------------------------------------------------------------------bool DeviceSimulatorThread::TransferUdFiles(){bool success = true;// TODO: configurable?const int retries = 5;vector<AnsiString>::iterator file = m_udFiles.begin();if( file != m_udFiles.end() ){// Retry a transfer if we fail.. check connection in between// incase it has droppedsuccess = m_device->sendUdFile( (*file).c_str(), 0, true, false );if( success ){m_udFiles.erase( file );}else if( m_running ){m_error.sprintf( "Failed to transfer UD file %s", (*file) );}}return success;}//---------------------------------------------------------------------------void __fastcall DeviceSimulatorThread::UploadUDFile( const AnsiString & filename ){if( m_running ){m_udFiles.push_back( filename );ReleaseSemaphore( m_semaphore, 1, NULL );}}//---------------------------------------------------------------------------void __fastcall DeviceSimulatorThread::Stop(){// Will stop the thread after the UD queue has finished transferringm_running = false;ReleaseSemaphore( m_semaphore, 1, NULL );}//---------------------------------------------------------------------------void DS_STDCALL DeviceSimulatorThread::onEvent( const unsigned short type,const char * msg,const unsigned char status ){switch( type ){case EVENT_UDXFER:break;case EVENT_DISCON:// Simply wake the main thread; it will handle a reconnectionReleaseSemaphore( m_semaphore, 1, NULL );break;}}//---------------------------------------------------------------------------void DS_STDCALL DeviceSimulatorThread::detach(){// TODO: This is fatal as we rely on event callbacks for processingm_device->detachListener( this );}