Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2263 kivins 1
//---------------------------------------------------------------------------
2
 
3
#include <vcl.h>
4
#pragma hdrstop
5
 
6
#include "DeviceSimulatorThread.h"
7
#include "IDeviceFactory.h"
8
#pragma package(smart_init)
9
//---------------------------------------------------------------------------
10
 
11
//   Important: Methods and properties of objects in VCL can only be
12
//   used in a method called using Synchronize, for example:
13
//
14
//      Synchronize(UpdateCaption);
15
//
16
//   where UpdateCaption could look like:
17
//
18
//      void __fastcall DeviceSimulatorThread::UpdateCaption()
19
//      {
20
//        Form1->Caption = "Updated in a thread";
21
//      }
22
//---------------------------------------------------------------------------
23
 
24
using namespace std;
25
 
26
__fastcall DeviceSimulatorThread::DeviceSimulatorThread( IDevice * device,
27
                                                         IDeviceFactory * factory,
28
                                                         const AnsiString & hostname ) :
29
    TThread( false ),
30
    m_device( device ),
31
    m_factory( factory ),
32
    m_address( hostname ),
33
    m_running( false ),
34
    m_error( "" )
35
{
36
    m_device->registerListener( this );
37
 
38
    SECURITY_ATTRIBUTES attribs = { 0 };
39
    attribs.nLength = sizeof( attribs );
40
    attribs.bInheritHandle = false;
41
 
42
    m_semaphore = CreateSemaphore( &attribs, 0, 10000, "DeviceSimulatorSemaphore" );
43
}
44
//---------------------------------------------------------------------------
45
 
46
void DeviceSimulatorThread::SetName()
47
{
48
    THREADNAME_INFO info;
49
    info.dwType = 0x1000;
50
    info.szName = "DeviceSimulatorThread";
51
    info.dwThreadID = -1;
52
    info.dwFlags = 0;
53
 
54
    __try
55
    {
56
         RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD),(DWORD*)&info );
57
    }
58
    __except (EXCEPTION_CONTINUE_EXECUTION)
59
    {
60
    }
61
}
62
 
63
//---------------------------------------------------------------------------
64
void __fastcall DeviceSimulatorThread::Execute()
65
{
66
    SetName();
67
    m_running = true;
68
 
69
    try
70
    {
71
        // Connect the device
72
 
73
        if( !m_device->connect( m_address.c_str() ) )
74
        {
75
            m_error = "Device failed to connect to Site Computer at " + m_address + ":5003";
76
        }
77
 
78
        // Loop until exit, or an error has occured
79
 
80
        while( m_running && m_error.IsEmpty() )
81
        {
82
            // Wait for:
83
            //  1. A disconnection/connection event to reconnect or update our status
84
            //  2. A request to upload a UD file from our manager
85
            //  3. A termination request
86
 
87
            if( WaitForSingleObject( m_semaphore, INFINITE ) == WAIT_OBJECT_0 )
88
            {
89
                // Check connection state
90
 
91
                if( !m_device->isConnected() )
92
                {
93
                    Reconnect();
94
                }
95
 
96
                // Perform any transfers required
97
 
98
                TransferUdFiles();
99
                ReleaseSemaphore( m_semaphore, 1, NULL );
100
            }
101
        }
102
    }
103
    __finally
104
    {
105
        // Terminate and cleanup. Destroy the device using the factory or
106
        // exceptions will be raised.
107
 
108
        m_device->detachListener( this );
109
        m_device->disconnect();
110
        m_running = false;
111
 
112
        m_factory->destroyDevice( *m_device );
113
        m_device = 0;
114
 
115
        CloseHandle( m_semaphore );
116
    }
117
}
118
//---------------------------------------------------------------------------
119
 
120
void DeviceSimulatorThread::Reconnect()
121
{
122
    //TODO: configurable?
123
    const int retries = 5;
124
 
125
    if( !m_device->isConnected() )
126
    {
127
        bool connected = false;
128
        int connectCount = retries;
129
 
130
        while( (connectCount >= 0) && !connected )
131
        {
132
            m_device->connect( m_address.c_str() );
133
            connectCount--;
134
 
135
            int checkCount = retries;
136
            while( (checkCount >= 0) && !(connected = m_device->isConnected()) )
137
            {
138
                checkCount--;
139
                Sleep( 500 );
140
            }
141
        }
142
 
143
        // Terminate if we couldn't get a connection
144
 
145
        if( !connected )
146
        {
147
            m_error.sprintf( "Failed to connect to site computer %s", m_address );
148
        }
149
    }
150
}
151
//---------------------------------------------------------------------------
152
 
153
bool DeviceSimulatorThread::TransferUdFiles()
154
{
155
    bool success = true;
156
 
157
    // TODO: configurable?
158
    const int retries = 5;
159
 
160
    vector<AnsiString>::iterator file = m_udFiles.begin();
161
    if( file != m_udFiles.end() )
162
    {
163
        // Retry a transfer if we fail.. check connection in between
164
        // incase it has dropped
165
 
166
        success = m_device->sendUdFile( (*file).c_str(), 0, true, false );
167
 
168
        if( success )
169
        {
170
            m_udFiles.erase( file );
171
        }
172
        else if( m_running )
173
        {
174
            m_error.sprintf( "Failed to transfer UD file %s", (*file) );
175
        }
176
    }
177
 
178
    return success;
179
}
180
//---------------------------------------------------------------------------
181
 
182
void __fastcall DeviceSimulatorThread::UploadUDFile( const AnsiString & filename )
183
{
184
    if( m_running )
185
    {
186
        m_udFiles.push_back( filename );
187
        ReleaseSemaphore( m_semaphore, 1, NULL );
188
    }
189
}
190
//---------------------------------------------------------------------------
191
 
192
void __fastcall DeviceSimulatorThread::Stop()
193
{
194
    // Will stop the thread after the UD queue has finished transferring
195
 
196
    m_running = false;
197
    ReleaseSemaphore( m_semaphore, 1, NULL );
198
}
199
//---------------------------------------------------------------------------
200
 
201
void DS_STDCALL DeviceSimulatorThread::onEvent( const unsigned short type,
202
                                                const char * msg,
203
                                                const unsigned char status )
204
{
205
    switch( type )
206
    {
207
    case EVENT_UDXFER:
208
        break;
209
 
210
    case EVENT_DISCON:
211
        // Simply wake the main thread; it will handle a reconnection
212
        ReleaseSemaphore( m_semaphore, 1, NULL );
213
        break;
214
    }
215
}
216
//---------------------------------------------------------------------------
217
 
218
void DS_STDCALL DeviceSimulatorThread::detach()
219
{
220
    // TODO: This is fatal as we rely on event callbacks for processing
221
    m_device->detachListener( this );
222
}