Subversion Repositories factorylink.im-bas

Rev

Rev 8 | Details | Compare with Previous | Last modification | View Log

Rev Author Line No. Line
1 mjordaan 1
// MyFlTask.cpp: implementation of the MyFlTask class.
2
//
3
//////////////////////////////////////////////////////////////////////
4
#include "stdafx.h"
5
#include "stdarg.h"
6
#include "MyFlTask.h"
7
#include "Registration.h"
8
#include "math.h"
9
#include "hklm.h"
10
 
9 Marcel 11
#pragma warning(disable : 4996)
12
 
1 mjordaan 13
#ifdef _DEBUG
14
#undef THIS_FILE
15
static char THIS_FILE[]=__FILE__;
16
#define new DEBUG_NEW
17
#endif
18
 
19
//static varibales for MyFlTask
20
//error codes which change the runtime manager status to error
21
int MyFlTask::m_iRunTimeError[ MAX_ERROR];   
22
int MyFlTask::m_iPreviousState;
23
 
24
 
25
/////////////////////////////////////////////////////////////////////////////
26
// Description: Thread function for the 'read' and 'write' functionality of the
27
// driver. The thread receives commands from an IO-translator, the imx-library
28
// is used to receive these commands. The command is dispatched to the appropiate 
29
// function of the device: read or write. the imx-library delivers an imx-dataset 
30
// with the command, this datasets belongs to a device.
31
// 
32
// Parameter: *ImxDevice - Pointer to imx device structure, this strucuture is 
33
// defined in the imx-library. 
34
// Parameter: function - functionality of the thread: read (FNC_READ) or write
35
// (FNC_WRITE).
36
// 
37
// Returns: on exit of the thread zero is returned.
38
// 
39
// Comment: 
40
// 
41
/////////////////////////////////////////////////////////////////////////////
42
int MyFlTask::ReadThreadFunction( IMX_DEVICE *ImxDevice, int function)
43
{
44
 
45
  CDeviceObject  *device = NULL;
46
  IMXDS          *ds = NULL;
47
  char           buf[ 2*sizeof( DEV_STATUS)];
48
  FLMSG          msgbuf;
49
  CDatasetObject *dataset;
50
  IMXSYSTEM      imxsys;
51
 
52
 
53
  //initialize the buffer for IMX
54
  msgbuf.m_ptr = buf;
55
  msgbuf.m_max = 2*sizeof( DEV_STATUS);
56
 
57
  //retrieve the pointer to the additional device information
58
  device = (CDeviceObject *)Imx_MT_Get_DevInfo( ImxDevice);
59
 
60
  //loop around forever and handle all IM-BAS read/write requests for this device
61
  while ( !Imx_MT_Get_Stop() )
62
  {
63
 
64
    //wait for a dataset read/write command
65
    if ( Imx_MT_Wait( ImxDevice, function, &ds ) != GOOD )
66
      break;
67
 
68
    //check first the type of the command, this should only be read or write
69
    switch (Imx_Get_Type( ds))
70
    {
71
 
72
      //read request, read data from device and send response to Io-xlator
73
      case IMX_READ_REQ:
74
 
75
        //retrieve the additional dataset information
76
        dataset = (CDatasetObject *)Imx_Get_Udata_Ptr( ds );
77
 
78
        //check dataset type
79
        if (dataset && (dataset->GetType() == 999))
80
        {
81
 
82
          device->GetDeviceStatus( buf+sizeof( IMXHDR));
83
 
84
          //do a prepare for retrieving registered values
85
          Imx_Ds_Prepare  ( ds, &msgbuf );
86
          Imx_Set_Type    ( ds, IMX_READ_RSP );
87
 
88
          //set the length of the received data
89
          Imx_Set_Start( ds, 0);
90
          Imx_Set_Len( ds, sizeof( DEV_STATUS) / Imx_Get_Boundary( ds));
91
 
92
          //send data to decoder
93
          LockRTDB( false);
94
 
95
          //fill imx structure with correct task id
96
          imxsys.task_id = GetId();
97
 
98
          //send imx message to translator
99
          Imx_Send( &imxsys, ds);
100
          ReleaseRTDB();
101
        }
102
        else
103
          device->Read( ds);
104
 
105
        break;
106
 
107
      //write request, send data to device and send response to Io-xlator
108
      case IMX_WRITE_REQ:
109
 
110
        //retrieve the additional dataset information
111
        dataset = (CDatasetObject *)Imx_Get_Udata_Ptr( ds );
112
 
113
        //check dataset type
114
        if (dataset && (dataset->GetType() == 999))
115
        {
116
 
117
          //reset total counters
118
          device->ResetTotalCounters();
119
        }
120
        else
121
          device->Write( ds);
122
        break;
123
 
124
      default: break;; //unkown and not processed command
125
    }
126
  }
127
 
128
  //thread ends
129
  return 0;
130
} //ReadThreadFunction
131
 
132
 
133
struct _recvdata
134
{
135
 
136
  SOCKET sock;
137
  SOCKADDR_IN m_wAddress;
138
  MyFlTask *theTask;
139
  CWinThread *m_Thread;
140
};
141
 
142
/////////////////////////////////////////////////////////////////////////////
143
// Descripton: Thread function for the 'receive' functionality of the driver.
144
// The parameters passed with this function identify a connection with a re-
145
// mote subsystem. We have to wait for the first alive sign before we can 
146
// identify the subsystem and search a corresponding devic eobject.
147
//
148
// Parameters: pParam - Array of two pointers, the first pointer points to 
149
// SOCKET variable, and the second pointer pojnts to an address structure. The
150
// memory fro the data structure is allocated prior to creation of the thread,
151
// this memory is not released by the thread that created this thread, before
152
// this function exits, the memory should be released.
153
// 
154
// Returns: 
155
// 
156
// Comment: 
157
// 
158
/////////////////////////////////////////////////////////////////////////////
159
unsigned int MyFlTask::ReceiveThreadFunction( LPVOID pParam)
160
{
161
 
162
  //the parameter is a pointer to a _recvdata strucuture, 
163
  //this strucuture includes a socket, address specification
164
  //and a pointer to the task object
165
  struct _recvdata *ConnData = (struct _recvdata *)pParam;
166
  char buffer[ IMX_BUFFER_SIZE]; //physical buffer for read/write operations
167
  char imxbuf[ IMX_BUFFER_SIZE]; //physical buffer for imx responses
168
  int m_iConnected = DEVICE_NOT_CONNECTED; //connection info
169
  CDeviceObject *device = NULL;
170
  int start = 0, length = 0;
171
  int error = 0;
172
 
173
 
174
  ConnData->theTask->CodeTrace( _T("THREADSTART"), 4, EVENTLOG_INFORMATION_TYPE, 
9 Marcel 175
                              TRACE_TEXT, NULL, 0, ConnData->theTask->GetThreadDelay(), ConnData->sock);
1 mjordaan 176
 
177
  //before we start the thread is delayed, no message are received
178
  Sleep( ConnData->theTask->GetThreadDelay());
179
 
180
  //clear input buffer, don't TM will not survive this action
181
  //ConnData->theTask->ImBasPurgeRX( ConnData->sock);
182
 
183
  //physical connectin is present, wait for life sign to establish 
184
  //connection on application level
185
  short standby = 0;
186
  while (m_iConnected != DEVICE_CONNECTED)
187
  {
188
 
189
    //the first lifesign is received without time restriction
190
    //this is not needed, cause the remote will disconnect
191
    int type = 0;
192
    if (!ConnData->theTask->ImBasRecvMessage( ConnData->sock, (char *)buffer, &type, device))
193
    {
194
 
195
      //check for life sign message
196
      if (type == DS_LIFESIGN) 
197
      {
198
 
199
        //find our device 
200
        CString DevId = ConnData->theTask->ImBasGetSystemId( buffer, PROT_LIFESIGN_MSG);
201
 
9 Marcel 202
        ConnData->theTask->CodeTrace( _T("THREADLIFESIGN"), 4, EVENTLOG_INFORMATION_TYPE, 
203
                                      TRACE_TEXT, NULL, 0, DevId.GetBuffer(), ConnData->sock);
204
 
1 mjordaan 205
        //lock the device list, only this thread can search and update devices for
206
        //incoming connections
207
        ConnData->theTask->DeviceListLock();
208
 
209
        for (int i = 0; i < ConnData->theTask->DeviceCount(); i++)
210
        {
211
 
212
          //lifesign received, device present; we have a connection
213
          if (DevId == ConnData->theTask->GetDevice( i)->GetSubId())
214
          {
215
 
216
            //device is found
217
            device = ConnData->theTask->GetDevice( i);
218
 
219
            //do not accept a second connection on the device
220
            if (device->GetSocket() != INVALID_SOCKET) 
221
            {
222
 
223
              //if device is stored in array, remve it
224
              device->GetDriver()->RemoveReceiveSocket( device->GetSocket());
225
 
226
              //disconnect the present connection and proceed 
227
              device->Disconnect();
228
              //break; //breaking will save the previous connection
229
            }
230
 
231
            //stop processing lifesign if the driver is in standby mode
232
            if (standby = (short)device->GetDriver()->StandbyTag) break;
233
 
234
            device->SetSocket( ConnData->sock); 
235
            device->SetTime();
236
 
9 Marcel 237
            device->theTask->CodeTrace( _T("CONNECTION_SET_SOCKET"), 4, EVENTLOG_INFORMATION_TYPE, 
238
                                          TRACE_TEXT, NULL, 0, device->GetName(), device->GetSocket(),
239
                                          ConnData->sock);
240
 
1 mjordaan 241
            if (!(error = device->theTask->ImBasSendMessage( device, (char *)buffer, type + 100)))
242
            {
243
              m_iConnected = DEVICE_CONNECTED;
244
 
245
              device->theTask->CodeTrace( _T("CONNECTION_PRESENT"), 3, EVENTLOG_INFORMATION_TYPE, 
246
                                          TRACE_TEXT, NULL, 0, device->GetName());
247
 
248
              device->SetReceiveThread( ConnData->m_Thread);
249
            }
250
            else
251
              device->theTask->CodeTrace( _T("DEVICE_TXERR"), 3, EVENTLOG_INFORMATION_TYPE, 
252
                                          TRACE_TEXT, NULL, 0, error);
253
 
254
            device->SetProtocolError( 0); //clear protocol errors
255
 
256
            //write status to device
257
            device->UpdateConnection( m_iConnected);
258
 
259
            //connect only one device
260
            break;
261
          }
262
        }
263
 
264
        //release device list
265
        ConnData->theTask->DeviceListRelease();
266
      }
267
 
268
      if (error) break; //on errors disconnect TCP/IP connection
269
      if (standby) continue; //standby mode, device will disconnect
270
    }
271
 
272
    //sleep if we have to continue
273
    if (m_iConnected != DEVICE_CONNECTED)
274
      //ConnData->theTask->FlSleep( 500);
275
    {
276
 
277
      int idx = -1;
278
 
279
      //code trace
280
      if (device)
281
      {
282
 
283
        device->theTask->CodeTrace( _T("TCP_DISCONNECT"), 3, EVENTLOG_INFORMATION_TYPE, 
284
                                    TRACE_TEXT, NULL, 0, device->GetName());
285
 
286
        //update socket count in main thread
287
        idx = ConnData->theTask->GetDriver()->FindReceiveSocket( device->GetSocket());
288
 
289
        //disconnect and exit thread
290
        device->Disconnect();
291
      }
292
      else
293
      {
294
 
295
        ConnData->theTask->CodeTrace( _T("THREAD_DISCONNECT"), 3, EVENTLOG_INFORMATION_TYPE, 
296
                                      TRACE_TEXT, NULL, 0);
297
 
298
        //disconnect and exit thread
299
        closesocket( ConnData->sock);
300
 
301
        //update socket count in main thread
302
        //idx = ConnData->theTask->GetDriver()->FindReceiveSocket( ConnData->sock);
303
      }
304
 
305
      //mark socket as invalid
306
      if (device) 
307
      {
308
 
309
        ConnData->theTask->DeviceListLock();
310
        device->SetSocket( INVALID_SOCKET); 
311
        device->SetProtocolError( 0); //clear protocol errors
312
        ConnData->theTask->DeviceListRelease();
313
        device->ClearReceiveThread();
314
      }
315
 
316
      //update socket count in main thread
317
      ConnData->theTask->GetDriver()->RemoveReceiveSocket( ConnData->sock);
318
 
319
      //exit the receive thread if the connection is lost
320
      //free the memory from the connection data
321
      delete pParam;
322
 
323
      return 0;
324
    }
325
  }
326
 
327
  //we have an application connection, receive data and process
328
  while (!ConnData->theTask->IsListenCanceled() && (m_iConnected == DEVICE_CONNECTED) && !Imx_MT_Get_Stop())
329
  {
330
 
331
    FLMSG reply;
332
    int type = 0;
333
    int DataError;
334
    device->SetProtocolError( 0);
335
    int error = ConnData->theTask->ImBasRecvMessage( device->GetSocket(), (char *)buffer, &type, device);
336
    int len = 0;
337
    int end = 0;
338
 
339
    reply.m_ptr = &imxbuf[ PROT_HEADER_LEN - sizeof( IMXHDR)];
340
    reply.m_max = IMX_BUFFER_SIZE - PROT_HEADER_LEN;
341
    reply.m_len = 0;
342
 
9 Marcel 343
    device->theTask->CodeTrace( _T("TCP_SOCKET_CHECK"), 4, EVENTLOG_INFORMATION_TYPE, 
344
                                TRACE_TEXT, NULL, 0, device->GetName(), device->GetSocket(), ConnData->sock);
345
 
1 mjordaan 346
    //final check if somebody interfering with our connection...
347
    if (device->GetSocket() != ConnData->sock)
348
      error = ERR_SOCKET_HANDLE;
349
 
350
    if (device->GetCurrentImxDataset() == NULL)
351
    {
352
 
353
      //dataset is required for commands, but not for lifesigns or exceptions
354
      if ((type != DS_LIFESIGN) && (type != DS_EXCEPTION))
355
        error = ERR_IMXDS_INVALID;
356
    }
357
 
358
    //check if response is valid
359
    if (error)
360
    {
361
 
362
      //give rtm error message
363
      m_iConnected = DEVICE_DISCONNECTING;
364
      device->UpdateConnection( m_iConnected);
365
 
366
      //code trace
367
      device->theTask->CodeTrace( _T("TCP_DISCONNECT_ERR"), 3, EVENTLOG_INFORMATION_TYPE, 
368
                                  TRACE_TEXT, NULL, 0, device->GetName(), error);
369
 
370
      //update socket count in main thread
371
      //int idx = device->GetDriver()->FindReceiveSocket( device->GetSocket());
372
      int sock = device->GetSocket();
373
 
374
      //disconnect and exit thread
9 Marcel 375
      device->Disconnect(ConnData->sock);
1 mjordaan 376
 
377
      //check for pending commands
378
      for (int i = 0; i < 2; i++)
379
        if (device->GetCmdPending( i))
380
        {
381
 
382
          //Imx error response, response is only end if a ds is present on the device
383
          if (device->GetCurrentImxDataset())
384
            device->theTask->ImxSendError( device->GetCurrentImxDataset(), 
385
                                           i, ERR_DEVICE_NOT_CONNECTED, device);
386
 
387
          //preserve imx dataset
388
          device->LockImxDataset();
389
 
390
          //release read request
391
          device->SetCmdPending( i, 0);
392
 
393
          //release lock on imx dataset
394
          device->ReleaseImxDataset();
395
        }
396
 
397
      ConnData->theTask->DeviceListLock();
398
 
399
      //update connection status
400
      m_iConnected = DEVICE_NOT_CONNECTED;
401
      device->UpdateConnection( m_iConnected);
402
 
403
      device->GetDriver()->RemoveReceiveSocket( sock);
404
 
405
      //mark socket as invalid
406
      device->SetSocket( INVALID_SOCKET);
407
 
408
      ConnData->theTask->DeviceListRelease();
409
 
410
      device->ClearReceiveThread();
411
 
412
      //exit the receive thread if the connection is lost
413
      //free the memory from the connection data
414
      delete pParam;
415
 
416
      return 0;
417
    }
418
 
419
    //the meber function GetCurrentImxDataset() of the 'device' will now always
420
    //return a valid ds, there is no need to check this again, if there is no 
421
    //read or write registered GetCmdPendig should return zero...
422
 
423
    //check if a valid message is received
424
    if (!type && device->GetProtocolerror())
425
    {
426
 
427
      //check for pending commands
428
      for (int i = 0; i < 2; i++)
429
        if (device->GetCmdPending( i))
430
        {
431
 
432
          //Imx error response
433
          if (device->GetCurrentImxDataset() != NULL)
434
            device->theTask->ImxSendError( device->GetCurrentImxDataset(), 
435
                                           i, device->GetProtocolerror(), device);
436
 
437
          //preserve imx dataset
438
          device->LockImxDataset();
439
 
440
          //release read request
441
          device->SetCmdPending( i, 0);
442
 
443
          //release lock on imx dataset
444
          device->ReleaseImxDataset();
445
        }
446
 
447
      device->SetProtocolError( 0); //clear protocol errors
448
      continue; //continue with while loop
449
    }
450
 
451
    //data lenght of message
452
    len = device->theTask->ImBasGetDataLength( buffer, PROT_HEADER_LEN);
453
 
454
    //code trace
455
    device->theTask->CodeTrace( _T("MESSAGE_RX"), 3, EVENTLOG_INFORMATION_TYPE, 
456
                                TRACE_TEXT, NULL, 0, device->GetName(), type);
457
 
458
    //preserve imx dataset
459
    device->LockImxDataset();
460
 
461
    //Imx_Set_Len( (device->GetCurrentImxDataset()), len);
462
    //if (device->GetCurrentImxDataset())
463
    //  device->theTask->CodeTrace( _T("%s, ds=%d, len=%d"), 3, EVENTLOG_INFORMATION_TYPE, 
464
    //                              TRACE_TEXT, NULL, 0, device->GetName(), Imx_Get_Len( (device->GetCurrentImxDataset())), len);
465
 
466
    //handle the message
467
    switch (type)
468
    {
469
 
470
      case DS_LIFESIGN: //life sign
471
 
472
        //only reply when in normal mode
473
        if ((short)device->GetDriver()->StandbyTag) break;
474
 
475
        //check time between two conscutive lifesigns
476
        if (device->theTask->UseLifesignTimeout())
477
        {
478
 
479
          //check the timeout interval
480
          if (device->GetTime( true) > (device->GetAliveTime() + device->GetAliveTime()/5))
481
          {
482
 
483
            //update status tag
484
            device->UpdateStatus( ERR_LIFESIGN_TIMEOUT);
485
 
486
            //update runtime manager
487
            device->theTask->MyRunTimeManager( ERR_LIFESIGN_TIMEOUT, FLS_ERROR, _T("LIFESIGN_TIMEOUT"), 
488
                                               device->GetName(), device->GetAliveTime());
489
 
490
            //mark device as disconnecting, now we get out of the while loop
491
            if (device->theTask->DisconnectLifesignLoss())
492
              m_iConnected = DEVICE_DISCONNECTING;
493
 
494
            //update device status
495
            device->UpdateConnection( m_iConnected);
496
          }
497
        }
498
 
499
        //update receive time
500
        device->SetTime();
501
 
502
        //send reply
503
        error = device->theTask->ImBasSendMessage( device, NULL, type + 100);
504
        break;    
505
 
506
      case DS_COMMAND_BOOL:
507
 
508
        //check for pending write
509
        if (device->GetCmdPending( FNC_WRITE))
510
        {
511
 
512
          //check for limit errors, and reply to translator
513
          if (((CDatasetObject *)Imx_Get_Udata_Ptr( device->GetCurrentImxDataset()))->GetErrorOnLimit())
514
            device->theTask->ImxSendError( device->GetCurrentImxDataset(), FNC_WRITE, ERR_LIMIT_SET, device);
515
          else //reply to translator
516
            device->theTask->ImxSend( device->GetCurrentImxDataset(), IMX_WRITE_RSP, device);
517
 
518
          //mark write ready, release semaphore
519
          device->SetCmdPending( FNC_WRITE, 0);
520
        }
521
        else
522
        {
523
 
524
          //update runtime manger
525
          MyRunTimeManager( ERR_UNEXPECTED_MSG, FLS_ERROR, _T("DEV_UNEXPECTEDMSG"), device->GetName(), type);
526
 
527
          //unexpected message, error on device
528
          device->UpdateStatus( ERR_UNEXPECTED_MSG); 
529
        }
530
        break;
531
 
532
      case DS_PARAMETER_BOOL:
533
 
534
        if ((device->GetCmdPending( FNC_READ)) || (device->GetCmdPending( FNC_WRITE)))
535
        {
536
 
537
          //get the dataset definition and calculate the number of packets
538
          CDatasetObject *dataset = (CDatasetObject *)Imx_Get_Udata_Ptr( device->GetCurrentImxDataset());
539
 
540
          int rep = device->theTask->GetPacketCount( Imx_Get_Len( device->GetCurrentImxDataset()), dataset->GetType());
541
          //int dlen = 0;
542
 
543
          //first packet initialise start, size and data area          
544
          if (!device->GetResponseCount())
545
          {
546
 
547
            //reset start and length of dataset
548
            start = Imx_Get_Start( device->GetCurrentImxDataset());
549
            length = 0;
550
 
551
            //initialize the imx data to their default values
552
            device->theTask->ImBasInitImxData( imxbuf, IMX_BUFFER_SIZE - PROT_HEADER_LEN,
553
                                               device->theTask->ImBasGetDataType( buffer, IMX_BUFFER_SIZE));
554
          }
555
 
556
          //convert data to imx data layout
557
          DataError = device->theTask->ImBasData2Imx( imxbuf, buffer, device->GetCurrentImxDataset(),
558
                                                      start, &length);
559
 
560
          //save conversion and interpretation errors
561
          if (DataError) device->SetProtocolError( DataError);
562
 
563
          //update start and length of the received data, this start and length
564
          //is used for the imx dataset
565
//          if (!device->GetResponseCount())
566
//          {
567
 
568
//            imxstart = start;
569
//            imxlength = length;
570
//          }
571
//          else 
572
//          {
573
 
574
            //calculate end address
575
//            end = ((imxstart + imxlength) - (start + length)) > 0 ? (imxstart + imxlength): (start + length);
576
 
577
//            imxstart = start < imxstart ? start : imxstart;
578
//            imxlength = end - imxstart;
579
//          }
580
 
581
          if (device->GetResponseCount( 1) >= rep)
582
          {
583
 
584
            //prepare for retrieving registered values
585
            Imx_Ds_Prepare( device->GetCurrentImxDataset(), &reply);
586
 
587
            Imx_Set_Start( device->GetCurrentImxDataset(), start);
588
            if (Imx_Get_Len( device->GetCurrentImxDataset()) < length)
589
              Imx_Set_Len( device->GetCurrentImxDataset(), length);
590
 
591
            if (device->GetCmdPending( FNC_READ))
592
            {
593
 
594
              //reply to translator
595
              if (device->GetProtocolerror())
596
                device->theTask->ImxSendError( device->GetCurrentImxDataset(), FNC_READ, device->GetProtocolerror(), device);
597
              else
598
                device->theTask->ImxSend( device->GetCurrentImxDataset(), IMX_READ_RSP, device);
599
            }
600
            else
601
            {
602
 
603
              int myL = len > 0 ? 20: 0;
604
              int myX = device->theTask->ImBasGetDataCount( buffer, myL);
605
              device->theTask->CodeTrace( _T("%s, ds=%d, len=%d"), 3, EVENTLOG_INFORMATION_TYPE, 
606
                                  TRACE_TEXT, NULL, 0, device->GetName(), Imx_Get_Len( (device->GetCurrentImxDataset())), myX);
607
 
608
              myL = Imx_Get_Len( device->GetCurrentImxDataset());
609
              Imx_Set_Len( device->GetCurrentImxDataset(), myX);
610
 
611
              //send unsolicited data to IO-translator              
612
              device->theTask->ImxSend( device->GetCurrentImxDataset(), IMX_RCV_RDY, device, true);
613
              Imx_Set_Len( device->GetCurrentImxDataset(), myL);
614
 
615
              //check for limit errors, and reply to translator
616
              if (((CDatasetObject *)Imx_Get_Udata_Ptr( device->GetCurrentImxDataset()))->GetErrorOnLimit())
617
                device->SetProtocolError( ERR_LIMIT_SET);
618
 
619
              if (device->GetProtocolerror())
620
                device->theTask->ImxSendError( device->GetCurrentImxDataset(), FNC_WRITE, device->GetProtocolerror(), device);
621
              else //reply to translator
622
                device->theTask->ImxSend( device->GetCurrentImxDataset(), IMX_WRITE_RSP, device);
623
            }
624
 
625
            //mark write ready, release semaphore
626
            if (device->GetCmdPending( FNC_READ)) device->SetCmdPending( FNC_READ, 0);
627
            else device->SetCmdPending( FNC_WRITE, 0);
628
          }
629
        }
630
        else
631
        {
632
 
633
          //update runtime manger
634
          MyRunTimeManager( ERR_UNEXPECTED_MSG, FLS_ERROR, _T("DEV_UNEXPECTEDMSG"), device->GetName(), type);
635
 
636
          device->UpdateStatus( ERR_UNEXPECTED_MSG); //unexpected message, error on device
637
        }
638
        break;
639
 
640
      case DS_STATUS_BOOL:
641
      case DS_STATINFO_BOOL:
642
 
643
        if (device->GetCmdPending( FNC_READ))
644
        {
645
 
646
          //get the dataset definition and calculate th enumber of packets
647
          CDatasetObject *dataset = (CDatasetObject *)Imx_Get_Udata_Ptr( device->GetCurrentImxDataset());
648
 
649
          int rep = device->theTask->GetPacketCount( Imx_Get_Len( device->GetCurrentImxDataset()), dataset->GetType());
650
          //int dlen = 0;
651
 
652
          //first packet initialise start, size and data area          
653
          if (!device->GetResponseCount())
654
          {
655
 
656
            //reset start and length of dataset
657
            start = Imx_Get_Start( device->GetCurrentImxDataset());
658
            length = 0;
659
 
660
            //initialize the imx data to their default values
661
            device->theTask->ImBasInitImxData( imxbuf, IMX_BUFFER_SIZE - PROT_HEADER_LEN,
662
                                               device->theTask->ImBasGetDataType( buffer, IMX_BUFFER_SIZE));
663
          }
664
 
665
          //convert data to imx data layout
666
          DataError = device->theTask->ImBasData2Imx( imxbuf, buffer, device->GetCurrentImxDataset(), start, &length);
667
 
668
          //save conversion and interpretation errors
669
          if (DataError) device->SetProtocolError( DataError);
670
 
671
          //update start and length of the received data, this start and length
672
          //is used for the imx dataset
673
          //if (!device->GetResponseCount()) imxstart = start;
674
          //else imxstart = start < imxstart ? start : imxstart;
675
          //imxlength += length; //length always increases
676
 
677
          if (device->GetResponseCount( 1) >= rep)
678
          {
679
 
680
            //prepare for retrieving registered values
681
            Imx_Ds_Prepare( device->GetCurrentImxDataset(), &reply);
682
 
683
            Imx_Set_Start( device->GetCurrentImxDataset(), start);
684
            if (Imx_Get_Len( device->GetCurrentImxDataset()) < length)
685
              Imx_Set_Len( device->GetCurrentImxDataset(), length);
686
 
687
            //reply to translator
688
            if (device->GetProtocolerror())
689
              device->theTask->ImxSendError( device->GetCurrentImxDataset(), FNC_READ, device->GetProtocolerror(), device);
690
            else
691
              device->theTask->ImxSend( device->GetCurrentImxDataset(), IMX_READ_RSP, device);
692
 
693
            //mark write ready, release semaphore
694
            device->SetCmdPending( FNC_READ, 0);
695
          }
696
        }
697
        else
698
        {
699
 
700
          //update runtime manger
701
          MyRunTimeManager( ERR_UNEXPECTED_MSG, FLS_ERROR, _T("DEV_UNEXPECTEDMSG"), device->GetName(), type);
702
 
703
          device->UpdateStatus( ERR_UNEXPECTED_MSG); //unexpected message, error on device
704
        }
705
        break;
706
 
707
      case DS_EXCEPTION:
708
      {
709
        device->SetReplySequence( device->theTask->ImBasGetSequence( buffer, PROT_HEADER_LEN));
710
 
711
        //exception message received, find dataset
712
        for (int i = 0, sendonce = 0; i < device->GetDatasetCount(); i++)
713
        {
714
 
715
          //reply to exception datasets
716
          if (device->GetDataSet( i)->GetType() == DS_EXCEPTION)
717
          {
718
 
719
            reply.m_ptr = &buffer[ PROT_HEADER_LEN - sizeof( IMXHDR)];
720
 
721
            //convert from UTC to local time, time is asumed to be of the 
722
            //form: hhmmss, that is six bytes.
723
            //conversion depends on the time format of the device
724
            if (!device->GetTimeFormat()) 
725
              device->theTask->ImBasUtc2Local( &buffer[ PROT_HEADER_LEN]);
726
            else
727
              device->theTask->ImBasLocal2Utc( &buffer[ PROT_HEADER_LEN]);
728
 
729
            CString tmp = _T("");
730
            int offset = device->theTask->GetExceptionSize( 0);
8 mjordaan 731
            int k;
1 mjordaan 732
 
733
            //strip spaces from equipment
8 mjordaan 734
            for (k = 0; k < device->theTask->GetExceptionSize( 1); k++)
1 mjordaan 735
                tmp.Insert( k+1, buffer[ PROT_HEADER_LEN + k + offset]);
736
 
737
            if (device->theTask->GetSpaceTrimLeft())tmp.TrimLeft();
738
            if (device->theTask->GetSpaceTrimRight()) tmp.TrimRight();
739
 
740
            //clear data buffer
741
            memset( &buffer[ PROT_HEADER_LEN + offset], 0, device->theTask->GetExceptionSize( 1));
742
            for (k = 0; k < tmp.GetLength(); k++)
743
              buffer[ PROT_HEADER_LEN + k + offset] = tmp.GetAt( k);
744
 
745
            tmp.Empty();
746
 
747
            //strip space from description
748
            offset = device->theTask->GetExceptionSize( 0) + device->theTask->GetExceptionSize( 1) + device->theTask->GetExceptionSize( 2);
749
            for (k = 0; k < device->theTask->GetExceptionSize( 3); k++)
750
                tmp.Insert( k+1, buffer[ PROT_HEADER_LEN + k + offset]);
751
 
752
            if (device->theTask->GetSpaceTrimLeft())tmp.TrimLeft();
753
            if (device->theTask->GetSpaceTrimRight()) tmp.TrimRight();
754
 
755
            //clear data buffer
756
            memset( &buffer[ PROT_HEADER_LEN + offset], 0, device->theTask->GetExceptionSize( 1));
757
            for (k = 0; k < tmp.GetLength(); k++)
758
              buffer[ PROT_HEADER_LEN + k + offset] = tmp.GetAt( k);
759
 
760
            //prepare for retrieving registered values
761
            Imx_Ds_Prepare( device->GetDataSet( i)->GetImxDataset(), &reply);
762
 
763
            Imx_Set_Start( device->GetDataSet( i)->GetImxDataset(), 0);
764
            Imx_Set_Len( device->GetDataSet( i)->GetImxDataset(), 
765
                         device->theTask->ImBasGetExceptionLength());
766
 
767
            //reply to translator
768
            device->theTask->ImxSend( device->GetDataSet( i)->GetImxDataset(), IMX_RCV_RDY, device);
769
            //reply.m_ptr = &imxbuf[ PROT_HEADER_LEN - sizeof( IMXHDR)];
770
 
771
            //send only one reply to TM
772
            if (sendonce == 0)
773
            {
774
 
775
              //send reply message to TM
776
              error = device->theTask->ImBasSendMessage( device, (char *)buffer, DSW_EXCEPTION);
777
 
778
              //sending failed, send error and completion to IOX
779
              if (error)
780
                device->theTask->MyRunTimeManager( error, FLS_ERROR, _T("DEVICE_READ_ERROR"), 
781
                                                   (char *)((LPCTSTR)device->GetName()), 
782
                                                   (char *)((LPCTSTR)device->GetDataSet( i)->GetName()),
783
                                                   error);
784
              sendonce = 1;
785
            }
786
          }
787
        }
788
        break;
789
      }
790
      case DSW_COMMAND_BOOL: //command confirmation
791
      case DSW_COMMAND_INT: //command confirmation
792
      case DSW_COMMAND_LONG: //command confirmation
793
      case DSW_COMMAND_REAL: //command confirmation
794
      case DSW_COMMAND_CHAR: //command confirmation
795
 
796
        //send reply
797
        error = device->theTask->ImBasSendMessage( device, (char *)buffer, type + 100);
798
 
799
        //check for pending write
800
        if (device->GetCmdPending( FNC_WRITE))
801
        {
802
 
803
          //check for limit errors, and reply to translator
804
          if (((CDatasetObject *)Imx_Get_Udata_Ptr( device->GetCurrentImxDataset()))->GetErrorOnLimit())
805
            device->theTask->ImxSendError( device->GetCurrentImxDataset(), FNC_WRITE, ERR_LIMIT_SET, device);
806
          else //reply to translator
807
            device->theTask->ImxSend( device->GetCurrentImxDataset(), IMX_WRITE_RSP, device);
808
 
809
          //mark write ready, release semaphore
810
          device->SetCmdPending( FNC_WRITE, 0);
811
        }
812
        else
813
        {
814
 
815
          //update runtime manger
816
          MyRunTimeManager( ERR_UNEXPECTED_MSG, FLS_ERROR, _T("DEV_UNEXPECTEDMSG"), device->GetName(), type);
817
 
818
          device->UpdateStatus( ERR_UNEXPECTED_MSG); //unexpected message, error on device
819
        }
820
        break;
821
    } //end if switch (type) 
822
 
823
    //release use of imx dataset
824
    device->ReleaseImxDataset();
825
  } //end of while (!ConnData->theTask->IsListenCanceled() && (m_iConnected == DEVICE_CONNECTED))
826
 
827
  //mark device as disconnecting
828
  m_iConnected = DEVICE_DISCONNECTING;
829
  device->UpdateConnection( m_iConnected);
830
 
831
  //code trace
832
  device->theTask->CodeTrace( _T("TCP_DISCONNECT"), 3, EVENTLOG_INFORMATION_TYPE, 
833
                              TRACE_TEXT, NULL, 0, device->GetName());
834
 
835
  //update socket count in main thread
836
  //int idx = device->GetDriver()->FindReceiveSocket( device->GetSocket());
837
  SOCKET sock = device->GetSocket();
838
 
839
  //disconnect and exit thread
840
  device->Disconnect();
841
 
842
  //check for pending commands
843
  for (int i = 0; i < 2; i++)
844
    if (device->GetCmdPending( i))
845
    {
846
 
847
      //Imx error response
848
      device->theTask->ImxSendError( device->GetCurrentImxDataset(), 
849
                                     i, ERR_DEVICE_NOT_CONNECTED, device);
850
 
851
      //preserve imx dataset
852
      device->LockImxDataset();
853
 
854
      //release read request
855
      device->SetCmdPending( i, 0);
856
 
857
      //release lock on imx dataset
858
      device->ReleaseImxDataset();
859
    }
860
 
861
  ConnData->theTask->DeviceListLock();
862
 
863
  m_iConnected = DEVICE_NOT_CONNECTED;
864
  device->UpdateConnection( m_iConnected);
865
 
866
  //reset errors on this device
867
  device->SetProtocolError( 0);
868
 
869
  ConnData->theTask->DeviceListRelease();
870
 
871
  device->GetDriver()->RemoveReceiveSocket( sock);
872
 
873
  //mark socket as invalid
874
  device->SetSocket( INVALID_SOCKET);
875
 
876
  device->ClearReceiveThread();
877
 
878
  //free the memory from the connection data
879
  delete pParam;
880
 
881
  return 0;
882
} //ReceiveThreadFunction
883
 
884
 
885
/////////////////////////////////////////////////////////////////////////////
886
// Descripton: Listen thread for accepting requests.
887
// 
888
// Parameters: 
889
// 
890
// Returns: 
891
// 
892
// Comment: 
893
// 
894
/////////////////////////////////////////////////////////////////////////////
895
unsigned int MyFlTask::MyListenThread( LPVOID pParam)
896
{
897
 
898
  CDriverObject *driver = (CDriverObject *)pParam;
899
  int error = 0;
900
  SOCKADDR_IN m_wAddress;
9 Marcel 901
  int addr_len = sizeof(SOCKADDR_IN);
1 mjordaan 902
 
9 Marcel 903
 
1 mjordaan 904
  //fill in local address
905
  m_wAddress.sin_family = AF_INET;
906
 
907
  //no local address specified ,all addresses qualify
908
  m_wAddress.sin_addr.s_addr = INADDR_ANY;
909
 
910
  //local address is specified on the driver object, first check
911
  //if the specified address is a valid TCP/IP address, if not
912
  //assume a name
913
  if (driver->GetIP().GetLength())
914
  {
915
 
916
 
917
    //check ip-address for punctuation
918
    if ((m_wAddress.sin_addr.s_addr = inet_addr( driver->GetIP())) == INADDR_NONE)
919
    {
920
 
921
      struct HOSTENT *haddr = (HOSTENT *)gethostbyname( driver->GetIP());
922
 
923
      //get ip-address from hostname
924
      if (!(gethostbyname( driver->GetIP())))
925
        m_wAddress.sin_addr.s_addr = INADDR_ANY;
926
      else
927
      {
928
 
929
        //hostname found, assume it is our name so we can use the IP-addres
930
        //m_wAddress.sin_addr.s_addr = INADDR_ANY;
931
 
932
        m_wAddress.sin_addr.s_addr = *((unsigned long *)gethostbyname( driver->GetIP())->h_addr);
933
      }
934
    }
935
  }
936
 
937
  //fill in the local port number
938
  m_wAddress.sin_port = htons( driver->GetLocalPort());
939
 
940
  //show the used network address inet_ntoa
941
  driver->theTask->CodeTrace( _T("TCP_ADDRESS"), 3, EVENTLOG_INFORMATION_TYPE, 
942
                              TRACE_TEXT, NULL, 0, inet_ntoa( m_wAddress.sin_addr), 
943
                              driver->GetLocalPort());
944
 
945
  //start with creation of a socket
946
  error = driver->CreateListenSocket();
947
 
948
  //bind the socket to the local port
949
  if (!error)
950
    error = bind( driver->GetListenSocket(), 
951
                  (SOCKADDR *)&m_wAddress, 
952
                  sizeof( m_wAddress));
953
 
954
  //thread is active untill a shutdown is received
955
  while (true)
956
  {
957
 
958
    //check if we still accept connections
959
    if ((short)driver->DisconnectTag)
960
    {
961
 
962
      //close socket, and rejected incoming requests
963
      driver->theTask->FlSleep( 100);
964
      continue;
965
    }
966
 
967
    //error handling
968
    if (error)
969
    {
970
 
971
      //check socket
972
      error = WSAGetLastError();
973
 
974
      if (driver->theTask->IsListenCanceled()) break;
975
 
976
      //RTM shows the error code
977
      MyRunTimeManager( error, FLS_ERROR, _T("LISTEN_ERROR"), error);
978
 
979
      //there is an error, wait for some time
980
      driver->theTask->FlSleep( 500);
981
 
982
      //start with creation of a socket
983
      error = driver->CreateListenSocket();
984
 
985
      //bind the socket to the local port
986
      if (!error)
987
        error = bind( driver->GetListenSocket(), 
988
                      (SOCKADDR *)&m_wAddress, 
989
                      sizeof( m_wAddress));
990
    }
991
 
992
    //set out a listen
993
    if (error = listen( driver->GetListenSocket(), SOMAXCONN)) continue;
994
 
995
    //save the socket and address i a structure and pass the variable to the thread
996
    struct _recvdata *tmp = new struct _recvdata;
997
 
998
    //continue if memory allocation failed
999
    if (!tmp) continue;
1000
 
1001
    //wait for incoming connection requests
9 Marcel 1002
    addr_len = sizeof(SOCKADDR_IN);
1003
    tmp->sock = accept( driver->GetListenSocket(), (struct sockaddr *)&tmp->m_wAddress, &addr_len);
1 mjordaan 1004
 
1005
    if (tmp->sock == INVALID_SOCKET)
1006
    {
1007
      error = -1;
1008
      delete tmp;
1009
      continue;
1010
    }
1011
 
1012
    //check if we still accept connections
1013
    if ((short)driver->DisconnectTag)
1014
    {
1015
 
9 Marcel 1016
      driver->theTask->CodeTrace( _T("CONNECTION_REJECTED"), 3, EVENTLOG_INFORMATION_TYPE, 
1017
                                  TRACE_TEXT, NULL, 0, inet_ntoa( tmp->m_wAddress.sin_addr), 
1018
                                  tmp->m_wAddress.sin_port);
1019
 
1 mjordaan 1020
      //close socket, and rejected incoming requests
1021
      closesocket( tmp->sock);
1022
      delete tmp;
1023
      continue;
1024
    }
1025
 
9 Marcel 1026
    driver->theTask->CodeTrace( _T("CONNECTION_INCOMING"), 3, EVENTLOG_INFORMATION_TYPE, 
1027
                                TRACE_TEXT, NULL, 0, inet_ntoa( tmp->m_wAddress.sin_addr), 
1028
                                tmp->m_wAddress.sin_port);
1029
 
1030
    driver->theTask->CodeTrace( _T("CONNECTION_ACCEPTED"), 4, EVENTLOG_INFORMATION_TYPE, 
1 mjordaan 1031
                                TRACE_TEXT, NULL, 0, driver->GetLocalPort(), tmp->sock);
1032
 
1033
    //set the task pointer
1034
    tmp->theTask = driver->theTask;
1035
 
1036
    //evaluate the connection and start a receive thread
1037
    CWinThread *m_RxThread = new CWinThread( ReceiveThreadFunction, (void *)tmp);
1038
 
1039
    if (m_RxThread == NULL)
1040
    {
1041
 
1042
      delete tmp;
1043
      error = ERR_RX_THREAD_CREATION;
1044
      continue;
1045
    }
1046
 
1047
    //auto clean up
1048
    m_RxThread->m_bAutoDelete = true;
1049
 
1050
    //register socket in array
1051
    //int idx = driver->AddReceiveSocket( tmp->sock);
1052
    driver->AddReceiveSocket( tmp->sock);
1053
    tmp->m_Thread = m_RxThread;
1054
 
1055
    //start the thread
1056
    if (!m_RxThread->CreateThread()) driver->RemoveReceiveSocket( tmp->sock);;
1057
  }
1058
 
1059
  //main thread has requested a stop, the main thread will shutdown
1060
  return 0;
1061
} //MyListenThread
1062
 
1063
 
1064
/////////////////////////////////////////////////////////////////////////////
1065
// Description: The 'EmptyEvent' funtion is an event function for FactoryLink,
1066
// however no action is done. Basicly the standard event function stores the
1067
// new tag value in the tag object, and that's all we need.
1068
// 
1069
// Parameter: *tag - Pointer to a tag object, this is the tag object with 
1070
// which the event function is registerd.
1071
// Parameter: *data - pointer to a user data structure. User is responsible 
1072
// for the structure, the pointer is tied to the event by registering the tag, 
1073
// event and data pointer.
1074
//
1075
// Returns: 
1076
// 
1077
// Comment: 
1078
// 
1079
/////////////////////////////////////////////////////////////////////////////
1080
void EmptyEvent( FlTag *tag, void *data)
1081
{
1082
 
1083
  CDriverObject *driver = (CDriverObject *)data;
1084
 
1085
 
1086
  //empty function, after this function call, the tag object is updated with
1087
  //the new value. This value is read by processing the event, here no action 
1088
  //is needed.
1089
  if (driver)
1090
    driver->theTask->CodeTrace( _T("TAG_EVENT"), 4, EVENTLOG_INFORMATION_TYPE, 
1091
                                TRACE_TEXT, NULL, 0, tag->Id().t_type, 
1092
                                tag->Id().t_data);
1093
} //EmptyEvent
1094
 
1095
 
1096
/////////////////////////////////////////////////////////////////////////////
1097
// Description: This event function handles the disconnect request from the 
1098
// FactoryLink kernel: a digital or analog tag. If the value changes from zero
1099
// to non-zero all connections to susbsystems are closed, and new incoming 
1100
// connection requests are rejected during the non-zero value of the tag.
1101
// 
1102
// Parameter: 
1103
// 
1104
// Returns: 
1105
// 
1106
// Comment: 
1107
// 
1108
/////////////////////////////////////////////////////////////////////////////
1109
void DisconnectEvent( FlTag *tag, void *data)
1110
{
1111
 
1112
  CDriverObject *driver = (CDriverObject *)data;
1113
 
1114
 
1115
  if (driver)
1116
    driver->theTask->CodeTrace( _T("DISCONNECT_EVENT"), 4, EVENTLOG_INFORMATION_TYPE, 
1117
                                TRACE_TEXT, NULL, 0, (short)tag->Value().ana);
1118
 
1119
  //tag vlaue is ON: disconnect all devices
1120
  if ((short)tag->Value().ana)
1121
  {
1122
 
1123
    // do not wait until all receive threads have ended
1124
    if (driver) driver->theTask->CancelReceiving( false);
1125
  }
1126
} //DisconnectEvent
1127
 
1128
 
1129
/////////////////////////////////////////////////////////////////////////////
1130
// Descripton: 
1131
// 
1132
// Parameters: 
1133
// 
1134
// Returns: 
1135
// 
1136
// Comment: 
1137
// 
1138
/////////////////////////////////////////////////////////////////////////////
1139
void ImxEvent( FlTag *tag, void *data)
1140
{
1141
 
1142
  struct _imxdata *idat = (struct _imxdata *)data;
1143
 
1144
 
1145
  //call the function
1146
  idat->imx_func( idat->data, tag->Value());
1147
 
1148
}
1149
 
1150
 
1151
//////////////////////////////////////////////////////////////////////
1152
// Construction/Destruction
1153
//////////////////////////////////////////////////////////////////////
1154
 
1155
//////////////////////////////////////////////////////////////////////
1156
// MyFlTask::MyFlTask( char *Name, char *Desc)
1157
// 
1158
// 
1159
//////////////////////////////////////////////////////////////////////
1160
MyFlTask::MyFlTask( char *Name, char *Desc)
1161
  : FlTask( Name, Desc)
1162
{
1163
 
1164
  //clear Imx variables
1165
  memset( (char *)&m_sImxSystem, 0, sizeof( IMXSYSTEM));
1166
 
1167
  m_ListenThread = NULL;
1168
  m_bStopListening = false;
1169
 
1170
  //default protocol version
1171
  m_sProtocolVersion = _T("02");
1172
 
1173
  //defualt number of IOX messages in mbx
1174
  m_iIoxMaxMbxMsg = 100;
1175
 
1176
  //default ini settings
1177
  m_sDestination = _T("BC");
1178
  m_sSource = _T("IM");
1179
  m_iTerminator = 10;
1180
  m_sDelimiter = ";";
1181
  m_sLifeSeq = _T("00");
1182
  m_iExceptionSize[ 0] = 6;
1183
  m_iExceptionSize[ 1] = 15;
1184
  m_iExceptionSize[ 2] = 1;
1185
  m_iExceptionSize[ 3] =50;
1186
  m_iExcLocalTime = 0;
1187
 
1188
  m_iAcceptIllegalException = 0;
1189
  m_iResponseTimeout = 5000;
1190
 
1191
  m_sIdLifeSign = _T("00");     //00
1192
  m_sIdCommand = _T("01");      //01
1193
  m_sIdParameter = _T("02");    //02
1194
  m_sIdSetParameter = _T("03"); //03
1195
  m_sIdStatus = _T("11");       //11
1196
  m_sIdStatistical = _T("12");  //12
1197
  m_sIdException = _T("21");    //21
1198
 
1199
  //space trimming is disabled by default
1200
  m_iSpaceTrimLeft = 0;
1201
  m_iSpaceTrimRight = 0;
1202
 
1203
  //non existent defualt value
1204
  m_iNonExistentValue = 0;
1205
 
1206
  //no debugging of reals
1207
  m_iDebugInfoForReals = 0;
1208
  m_iThreadDelaySec = 0; //no delay
1209
  m_iFirstLifeSign = 30;
1210
 
1211
  //no error on setting a limit
1212
  m_iErrorOnLimit = 0;
1213
 
1214
  //create a semaphore for exclusive usae of deice list
1215
  m_semDeviceList = CreateSemaphore( NULL, 1, 1, NULL);
1216
 
1217
  for( int i = 0; i < MAX_ERROR; i++)
1218
    m_iRunTimeError[ i] = 1;
1219
 
1220
  m_iPreviousState = -1;
1221
}
1222
 
1223
 
1224
//////////////////////////////////////////////////////////////////////
1225
// void MyFlTask::ExitApplication()
1226
// 
1227
// Something serious went wrong......, just exit application right now.
1228
//////////////////////////////////////////////////////////////////////
1229
void MyFlTask::ExitApplication( char *Xlate, ...)
1230
{
1231
 
1232
  va_list      vl;
1233
 
1234
 
1235
  //get the argument pointer
1236
  va_start( vl, Xlate);
1237
 
1238
  //execute the FL utility function to write the RTM tags
1239
  if (Xlate) MyRunTimeManager( -1, FLS_ERROR, Xlate, va_arg( vl, char *));
1240
 
1241
  va_end( vl);
1242
 
1243
  //continue with normal stopping of the task
1244
  Stopping();
1245
 
1246
  //all things for FL done, quit now
1247
  exit(-1);
1248
}
1249
 
1250
// Take each desktop and add it to the listbox.
1251
//BOOL CALLBACK MyDesktopEnumProc(LPTSTR name, LPARAM listbox)
1252
//{
1253
//	HWND hwndList = (HWND)listbox;
1254
//	SendMessage(hwndList, LB_ADDSTRING, 0,
1255
//		reinterpret_cast<LPARAM>(name));
1256
//	return TRUE;
1257
//}
1258
 
1259
//////////////////////////////////////////////////////////////////////
1260
// void MyFlTask::Registration()
1261
// 
1262
// Registraiton window if task is not registered
1263
//////////////////////////////////////////////////////////////////////
1264
void MyFlTask::Registration()
1265
{
1266
#ifdef MyLicensActive
1267
 
1268
  HDESK hdesk = OpenDesktop( "Default", 0, FALSE, DESKTOP_SWITCHDESKTOP);
1269
 
1270
  if (hdesk != NULL)
1271
  {
1272
 
1273
    //open registration box only for the default desktop 
1274
    CRegistration dlg( TASK_NUMBER);
1275
 
1276
    //check if applicaiton is registrated
1277
    if (!dlg.IsRegistered()) 
1278
    {
1279
 
1280
      //switch always to the default desktop
1281
      if (SwitchDesktop(hdesk))
1282
      {
1283
 
1284
        //show registration window
1285
        dlg.DoModal();
1286
 
1287
        //SwitchDesktop(hprev);
1288
        CloseDesktop(hdesk);
1289
      }
1290
    }
1291
  }
1292
 
1293
 
1294
/*
1295
 
1296
DWORD dwGuiThreadId = 0; 
1297
 
1298
int 
1299
UserMessageBox( 
1300
    RPC_BINDING_HANDLE h, 
1301
    LPSTR lpszWindowStation, 
1302
    LPSTR lpszDesktop, 
1303
    LPSTR lpszText, 
1304
    LPSTR lpszTitle, 
1305
    UINT fuStyle) 
1306
{ 
1307
        DWORD dwThreadId; 
1308
    HWINSTA hwinstaSave; 
1309
    HDESK hdeskSave; 
1310
    HWINSTA hwinstaUser; 
1311
    HDESK hdeskUser; 
1312
    HWND hwndOwner
1313
    int result; 
1314
 
1315
    // Ensure connection to service window station and desktop, and 
1316
    // save their handles. 
1317
 
1318
//    hwndOwner = GetDesktopWindow(); 
1319
    hwinstaSave = GetProcessWindowStation(); 
1320
    dwThreadId = GetCurrentThreadId(); 
1321
    hdeskSave = GetThreadDesktop(dwThreadId); 
1322
 
1323
    // Impersonate the client and connect to the User's 
1324
    // window station and desktop. 
1325
 
1326
    RpcImpersonateClient(h); 
1327
    hwinstaUser = OpenWindowStation(lpszWindowStation, FALSE, MAXIMUM_ALLOWED); 
1328
    if (hwinstaUser == NULL) 
1329
    { 
1330
        RpcRevertToSelf(); 
1331
        return 0; 
1332
    } 
1333
    SetProcessWindowStation(hwinstaUser); 
1334
    hdeskUser = OpenDesktop(lpszDesktop, 0, FALSE, MAXIMUM_ALLOWED); 
1335
    RpcRevertToSelf(); 
1336
    if (hdeskUser == NULL) 
1337
    { 
1338
        SetProcessWindowStation(hwinstaSave); 
1339
        CloseWindowStation(hwinstaUser); 
1340
        return 0; 
1341
    } 
1342
    SetThreadDesktop(hdeskUser); 
1343
 
1344
    // Display message box. 
1345
 
1346
    dwGuiThreadId = dwThreadId; 
1347
    result = MessageBox(NULL, lpszText, lpszTitle, fuStyle); 
1348
    dwGuiThreadId = 0; 
1349
 
1350
    // Restore window station and desktop. 
1351
 
1352
    SetThreadDesktop(hdeskSave); 
1353
    SetProcessWindowStation(hwinstaSave); 
1354
    CloseDesktop(hdeskUser); 
1355
    CloseWindowStation(hwinstaUser); 
1356
 
1357
    return result; 
1358
} 
1359
 
1360
*/
1361
#endif
1362
}
1363
 
1364
 
1365
//////////////////////////////////////////////////////////////////////
1366
// void MyFlTask::ReadSettings()
1367
// 
1368
// Read settings from the task ini file and store the values in the task
1369
// object.
1370
//////////////////////////////////////////////////////////////////////
1371
BOOL MyFlTask::ReadSettings()
1372
{
1373
 
1374
  CString sSection(_T("Debug"));
1375
 
1376
 
1377
  MyRunTimeManager( 0, FLS_STARTING, "INILOAD", GetIniFileName());
1378
 
1379
  //read the maximum nuber of messages for translaotro mailboxes
1380
  sSection = _T("Translator");
1381
  m_iIoxMaxMbxMsg = GetPrivateProfileInteger( sSection, _T("MaxMessage"), 100);
1382
 
1383
  if (GetPrivateProfileInteger( sSection, _T("UseBlackBox"), 1) != 0) 
1384
    hLibBlackBox = LoadLibrary( "BlackBox.dll");
1385
  else
1386
    hLibBlackBox = NULL;
1387
 
1388
  //go to next section
1389
  sSection = _T("Protocol");
1390
 
1391
  //load source and destination id's
1392
  m_sSource = GetPrivateProfileString( sSection, _T("Source"), _T("IM"));
1393
  if (m_sSource.GetLength() < 2) m_sSource = _T("IM");
1394
  if (m_sSource.GetLength() > 2) m_sSource = m_sSource.Left( 2);
1395
 
1396
  m_sDestination = GetPrivateProfileString( sSection, _T("Destination"), _T("BC"));
1397
  if (m_sDestination.GetLength() < 2) m_sDestination = _T("BC");
1398
  if (m_sDestination.GetLength() > 2) m_sDestination = m_sDestination.Left( 2);
1399
 
1400
  //load termintor character
1401
  m_iTerminator = GetPrivateProfileInteger( sSection, _T("Terminator"), 10);
1402
 
1403
  //load delimiter character
1404
  m_sDelimiter = GetPrivateProfileString( sSection, _T("Delimiter"), _T(";"));
1405
  if (m_sDelimiter.GetLength() != 2) m_sDelimiter = _T(";");
1406
 
1407
  //load version
1408
  m_sProtocolVersion = GetPrivateProfileString( sSection, _T("Version"), _T("02"));
1409
  if (m_sProtocolVersion.GetLength() < 2) m_sProtocolVersion = _T("02");
1410
  if (m_sProtocolVersion.GetLength() > 2) m_sProtocolVersion = m_sProtocolVersion.Left( 2);
1411
 
1412
  //load sequence number for life signs
1413
  m_sLifeSeq = GetPrivateProfileString( sSection, _T("LifeSeq"), _T("00"));
1414
  if (m_sLifeSeq.GetLength() < 2) m_sLifeSeq = _T("00");
1415
  if (m_sLifeSeq.GetLength() > 2) m_sLifeSeq = m_sLifeSeq.Left( 2);
1416
 
1417
  //load settings for exception message
1418
  m_iExceptionSize[ 0] = GetPrivateProfileInteger( sSection, _T("ExceptionByteLength0"), 6);
1419
  m_iExceptionSize[ 1] = GetPrivateProfileInteger( sSection, _T("ExceptionByteLength1"), 15);
1420
  m_iExceptionSize[ 2] = GetPrivateProfileInteger( sSection, _T("ExceptionByteLength2"), 1);
1421
  m_iExceptionSize[ 3] = GetPrivateProfileInteger( sSection, _T("ExceptionByteLength3"), 50);
1422
  m_iExceptionSize[ 4] = GetPrivateProfileInteger( sSection, _T("ExceptionByteLength4"), 0);
1423
  m_iExceptionSize[ 5] = GetPrivateProfileInteger( sSection, _T("ExceptionByteLength5"), 0);
1424
  m_iExceptionSize[ 6] = GetPrivateProfileInteger( sSection, _T("ExceptionByteLength6"), 0);
1425
  m_iExceptionSize[ 7] = GetPrivateProfileInteger( sSection, _T("ExceptionByteLength7"), 0);
1426
  m_iExceptionSize[ 8] = GetPrivateProfileInteger( sSection, _T("ExceptionByteLength8"), 0);
1427
  m_iExceptionSize[ 9] = GetPrivateProfileInteger( sSection, _T("ExceptionByteLength9"), 0);
1428
 
1429
  m_iExcLocalTime = GetPrivateProfileInteger( sSection, _T("ExceptionUseLocalTime"), 1);
1430
 
1431
  //trim leading and/or trailing spaces from strings
1432
  m_iSpaceTrimLeft = GetPrivateProfileInteger( sSection, _T("StringTrimLeft"), 0);
1433
  m_iSpaceTrimRight = GetPrivateProfileInteger( sSection, _T("StringTrimRight"), 0);
1434
 
1435
  if (GetPrivateProfileInteger( sSection, _T("StringTrimBothSides"), 0))
1436
    m_iSpaceTrimLeft = m_iSpaceTrimRight = 1;
1437
 
1438
  //read default value for numerical elements in case the TM reports them as non-existent
1439
  m_iNonExistentValue = GetPrivateProfileInteger( sSection, _T("NonExistentValue"), 0);
1440
 
1441
  //read requested behaviour for protocol errors: to disconnect or not
1442
  m_iDisconnectProtocolErrors = GetPrivateProfileInteger( sSection, _T("DisconnectProtocolErrors"), 1);
1443
 
1444
  m_iUseLifesignTimeout = GetPrivateProfileInteger( sSection, _T("UseLifesignTimeout"), 1);
1445
  m_iDisconnectLifesignLoss = GetPrivateProfileInteger( sSection, _T("DisconnectLifesignLoss"), 0);
1446
 
1447
  //load command identifiers
1448
  m_sIdLifeSign = GetPrivateProfileString( sSection, _T("IdLifeSign"), _T("00"));
1449
  if (m_sIdLifeSign.GetLength() < 2) m_sIdLifeSign = _T("00");
1450
  if (m_sIdLifeSign.GetLength() > 2) m_sIdLifeSign = m_sIdLifeSign.Left( 2);
1451
 
1452
  m_sIdCommand = GetPrivateProfileString( sSection, _T("IdCommand"), _T("01"));
1453
  if (m_sIdCommand.GetLength() < 2) m_sIdCommand = _T("01");
1454
  if (m_sIdCommand.GetLength() > 2) m_sIdCommand = m_sIdCommand.Left( 2);
1455
 
1456
  m_sIdParameter = GetPrivateProfileString( sSection, _T("IdParameter"), _T("02"));
1457
  if (m_sIdParameter.GetLength() < 2) m_sIdParameter = _T("02");
1458
  if (m_sIdParameter.GetLength() > 2) m_sIdParameter = m_sIdParameter.Left( 2);
1459
 
1460
  m_sIdSetParameter = GetPrivateProfileString( sSection, _T("IdSetParameter"), _T("03"));
1461
  if (m_sIdSetParameter.GetLength() < 2) m_sIdSetParameter = _T("03");
1462
  if (m_sIdSetParameter.GetLength() > 2) m_sIdSetParameter = m_sIdSetParameter.Left( 2);
1463
 
1464
  m_sIdStatus = GetPrivateProfileString( sSection, _T("IdStatus"), _T("11"));
1465
  if (m_sIdStatus.GetLength() < 2) m_sIdStatus = _T("11");
1466
  if (m_sIdStatus.GetLength() > 2) m_sIdStatus = m_sIdStatus.Left( 2);
1467
 
1468
  m_sIdStatistical = GetPrivateProfileString( sSection, _T("IdStatistical"), _T("12"));
1469
  if (m_sIdStatistical.GetLength() < 2) m_sIdStatistical = _T("12");
1470
  if (m_sIdStatistical.GetLength() > 2) m_sIdStatistical = m_sIdStatistical.Left( 2);
1471
 
1472
  m_sIdException = GetPrivateProfileString( sSection, _T("IdException"), _T("21"));
1473
  if (m_sIdException.GetLength() < 2) m_sIdException = _T("21");
1474
  if (m_sIdException.GetLength() > 2) m_sIdException = m_sIdException.Left( 2);
1475
 
1476
  m_iDebugInfoForReals = GetPrivateProfileInteger( sSection, _T("DebugInfoForReals"), 0);
1477
 
1478
  m_iThreadDelaySec = GetPrivateProfileInteger( sSection, _T("ThreadDelaySec"), 0);
1479
 
1480
  m_iErrorOnLimit = GetPrivateProfileInteger( sSection, _T("ErrorOnDataLimit"), 0);
1481
 
1482
  m_iFirstLifeSign = GetPrivateProfileInteger( sSection, _T("FirstLifeSign"), 30);
1483
 
1484
  m_iAcceptIllegalException = GetPrivateProfileInteger( sSection, _T("AllowInvalidExceptionLength"), 0);
1485
  m_iResponseTimeout = GetPrivateProfileInteger( sSection, _T("ResponseTimeout"), 5000);
1486
 
1487
  //go to next section
1488
  sSection = _T("RunTimeManagerError");
1489
 
1490
  //load error code passing to the runtime manager
1491
  CString StrError = _T("Error%d");
1492
  for( int i = 0; i < MAX_ERROR; i++)
1493
  {
1494
 
1495
    StrError.Format( _T("Error%d"), i);
1496
    m_iRunTimeError[ i] = GetPrivateProfileInteger( sSection, StrError, 1);
1497
  }
1498
 
1499
  //return to starting phase
1500
  MyRunTimeManager( 0, FLS_STARTING, "START");
1501
  return true;
1502
} //ReadSettings
1503
 
1504
//////////////////////////////////////////////////////////////////////
1505
// Overloaded functions
1506
//////////////////////////////////////////////////////////////////////
1507
 
1508
//////////////////////////////////////////////////////////////////////
1509
// void MyFlTask::CTload()
1510
// 
1511
// 
1512
//////////////////////////////////////////////////////////////////////
1513
void MyFlTask::CTload()
1514
{
1515
 
1516
  FlCTfile         CTfile;
1517
  int              i, ct;
1518
  CT_DRIVER        *driver_info;
1519
  CT_DEVICE        *device_info;
1520
  CT_DATASET       *dataset_info;
1521
  CDriverObject    *driverobject = NULL;
1522
  CDeviceObject    *deviceobject;
1523
  CDatasetObject   *datasetobject;
1524
 
1525
 
1526
  //mark previous state as starting
1527
  m_iPreviousState = FLS_STARTING;
1528
 
1529
  //first load settings from the ini-file
1530
  ReadSettings();
1531
 
1532
  //check for opened CT archive file
1533
  if (!CTfile.IsOpen() || (CTfile.NoTables() < 2))
1534
  {
1535
 
1536
    //adjust message according to situation 
1537
    if (CTfile.IsOpen()) ExitApplication( _T("NOTRIGGERS"));
1538
    else ExitApplication( _T("NOCT"));
1539
 
1540
    return;
1541
  }
1542
 
1543
  //loop through the tables, processing each in turn
1544
  for (ct = 0; ct < CTfile.NoTables(); ct++)
1545
  {
1546
 
1547
    //read the index for this table
1548
    if (CTfile.ReadIndex( ct) != GOOD)
1549
      continue;
1550
 
1551
    switch (CTfile.Type())
1552
    {
1553
 
1554
      //global definitions for the driver, only the first record is used
1555
      //all other records are read and stored but will never be used....
1556
      case CTID_DRIVER:
1557
 
1558
        //read the main record, this is the first record
1559
        driver_info = (CT_DRIVER *)CTfile.ReadRecord( 0);
1560
 
1561
        //generate an error message if there are no records
1562
        if (!driver_info)
1563
          ExitApplication( _T("NOHEADER"), _T("Driver"));
1564
 
1565
        //allocate memory for the new object
1566
        if (!(driverobject = new CDriverObject( driver_info, this)))
1567
          ExitApplication( _T("NOMEMORY"));
1568
 
1569
        //add element to list
1570
        m_aDriver.Add( (CDriverObject *)driverobject);
1571
 
1572
        //add standby tag as a trigger
1573
        if (driverobject->StandbyTag.IsValid())
1574
        {
1575
 
1576
          SetEvent( driverobject->StandbyTag, EmptyEvent, driverobject);
1577
 
1578
          //force change bits for standby tag to ON
1579
          SetChangeBits( &driverobject->StandbyTag);
1580
        }
1581
 
1582
        //add disconnect tag as a trigger
1583
        if (driverobject->DisconnectTag.IsValid())
1584
        {
1585
 
1586
          SetEvent( driverobject->DisconnectTag, DisconnectEvent, driverobject);
1587
 
1588
          //force change bits for disconnect tag to ON
1589
          SetChangeBits( &driverobject->DisconnectTag);
1590
        }
1591
        break;
1592
 
1593
      //load devcies, included are the datasets for th edevice
1594
      case CTID_DEVICE:
1595
 
1596
        //read the header of the CT, this is the device
1597
        device_info = (CT_DEVICE *)CTfile.ReadHeader();
1598
 
1599
        //allocate memory for the new object
1600
        if (!(deviceobject = new CDeviceObject( device_info, this)))
1601
          ExitApplication( _T("NOMEMORY"));;
1602
 
1603
        //add element to list
1604
        m_aDevice.Add( deviceobject);
1605
 
1606
        //relation between driver object and device
1607
        deviceobject->SetDriver( driverobject);
1608
 
1609
        //add triggers: 3 disable tag's, during processing only the new is sotred
1610
        //for later use
1611
        //force change bits for standby and disconnect tag to ON
1612
 
1613
        //read disable
1614
        if (deviceobject->ReadDisableTag.IsValid())
1615
        {
1616
 
1617
          SetEvent( deviceobject->ReadDisableTag, EmptyEvent, deviceobject);
1618
          SetChangeBits( &deviceobject->ReadDisableTag);
1619
        }
1620
 
1621
        //write disable
1622
        if (deviceobject->WriteDisableTag.IsValid())
1623
        {
1624
 
1625
          SetEvent( deviceobject->WriteDisableTag, EmptyEvent, deviceobject);
1626
          SetChangeBits( &deviceobject->WriteDisableTag);
1627
        }
1628
 
1629
        //receive disable
1630
        if (deviceobject->ReadDisableTag.IsValid())
1631
        {
1632
 
1633
          SetEvent( deviceobject->ReceiveDisableTag, EmptyEvent, deviceobject);
1634
          SetChangeBits( &deviceobject->ReceiveDisableTag);
1635
        }
1636
 
1637
        //read all the records of the CT, the recipients
1638
        for (i = 0; i < CTfile.NoRecords(); i++)
1639
        {
1640
 
1641
          //read the record
1642
          dataset_info = (CT_DATASET *)CTfile.ReadRecord( i);
1643
 
1644
          //allocate memory for the new object
1645
          if (!(datasetobject = new CDatasetObject( dataset_info, this)))
1646
            ExitApplication( _T("NOMEMORY"));;
1647
 
1648
          //check address info
1649
          if (datasetobject->GetStart() > PROT_MAX_LENGTH)
1650
          {
1651
 
1652
            datasetobject->SetStart( PROT_MAX_LENGTH);
1653
            MyRunTimeManager( ERR_DS_ADJUSTED, FLS_ERROR, _T("ADJUST_DS"), datasetobject->GetName(), 
1654
                              datasetobject->GetStart(), datasetobject->GetLength());
1655
          }
1656
 
1657
          if(datasetobject->GetStart() + datasetobject->GetLength() > PROT_MAX_LENGTH)
1658
          {
1659
 
1660
            datasetobject->SetLength( PROT_MAX_LENGTH + 1 - datasetobject->GetStart());
1661
            MyRunTimeManager( ERR_DS_ADJUSTED, FLS_ERROR, _T("ADJUST_DS"), datasetobject->GetName(), 
1662
                              datasetobject->GetStart(), datasetobject->GetLength());
1663
          }
1664
 
1665
          if (datasetobject->GetLength() > PROT_MAX_SIZE)
1666
          {
1667
 
1668
            datasetobject->SetLength( PROT_MAX_SIZE);
1669
            MyRunTimeManager( ERR_DS_ADJUSTED, FLS_ERROR, _T("ADJUST_DS"), datasetobject->GetName(), 
1670
                              datasetobject->GetStart(), datasetobject->GetLength());
1671
          }
1672
 
1673
          //add element to list in device object
1674
          deviceobject->AddDataSet( datasetobject);
1675
        }
1676
        break;
1677
    }
1678
  }
1679
}
1680
 
1681
 
1682
//////////////////////////////////////////////////////////////////////
1683
// void MyFlTask::Starting()
1684
// 
1685
// Application is starting, initialise our interface with FactoryLink.
1686
//////////////////////////////////////////////////////////////////////
1687
void MyFlTask::Starting()
1688
{
9 Marcel 1689
  unsigned long i;
1 mjordaan 1690
 
1691
  //call original function
1692
  FlTask::Starting();
1693
 
1694
  //this is a driver, so force polling mode if we have
1695
  //only 1 task id
1696
  if (!Is2TaskIdDriver()) ForcePollingMode();
1697
  else ForceEventMode();
1698
 
1699
  //check registration
1700
  Registration();
1701
 
1702
  //assume normal start up
1703
  m_iPreviousState = FLS_ACTIVE;
1704
 
1705
  //startup winsock, exit application when this fails
1706
  if (!FlTask::WSAStartUp()) ExitApplication( NULL);
1707
 
1708
  //check if the command line has a definition for the local station id
1709
  //this parameter is passed to the task with the cmd line option: -LSx
1710
  CString sLocalStation = GetCmdLineOption( _T("LS"));
1711
 
1712
  //initialise the IMX library
1713
  Imx_Sys_Set_Task_Id( &m_sImxSystem, GetMainId());
1714
  Imx_Sys_Set_Station_Id( &m_sImxSystem, atoi( sLocalStation));
1715
  Imx_Sys_Set_Mbx( &m_sImxSystem, m_aDriver.GetAt( 0)->MailboxTag.Id());
1716
  Imx_Sys_Set_Functions( &m_sImxSystem, IMX_READ_FNC|IMX_WRITE_FNC|IMX_RCV_FNC|IMX_QUERY_FNC);
1717
 
1718
  //initialise the IMX MT library, IMX library is initialized from this call
1719
  int imx_init = Imx_MT_Init( &m_sImxSystem);
1720
 
1721
  //quit if initialisation failed, continuing will give unpredictable errors
1722
  if (imx_init != GOOD)
1723
    ExitApplication( _T("IMX_INIT"), imx_init);
1724
 
1725
  //create the device structures for IMX, and link to device object
9 Marcel 1726
  for (i = 0; i < (unsigned long)m_aDevice.GetSize(); i++)
1 mjordaan 1727
  {
1728
 
1729
    CDeviceObject *device = m_aDevice.GetAt( i);
1730
 
1731
    device->ImxDevice = (IMX_DEVICE *)calloc( 1, sizeof( IMX_DEVICE));
1732
 
1733
    if (device->ImxDevice == NULL) 
1734
      ExitApplication( _T("NO_MEMORY"));
1735
 
1736
    //update connection state and tag
1737
    device->UpdateConnection( DEVICE_NOT_CONNECTED);
1738
 
1739
    //set additional device information for IMX
1740
    Imx_MT_Set_DevInfo( device->ImxDevice, device);
1741
 
1742
    //set the thread functions for every functionality
1743
    Imx_MT_Set_Thread( device->ImxDevice, IMX_MT_READ, ReadThreadFunction);
1744
    Imx_MT_Set_Thread( device->ImxDevice, IMX_MT_WRITE, NULL);
1745
    //Imx_MT_Set_Thread( device->ImxDevice, IMX_MT_RCV, ReceiveThreadFunction);
1746
    Imx_MT_Set_Thread( device->ImxDevice, IMX_MT_RCV, NULL);
1747
 
1748
    //clear communication buffers
1749
    device->ClearBuffer();
1750
 
1751
    //allocate communication buffers for IMX MT
1752
    FLMSG imx_buf;
1753
 
1754
    imx_buf.m_len = 0;
1755
    imx_buf.m_max = IMX_BUFFER_SIZE;
1756
 
1757
    imx_buf.m_ptr = device->GetBuffer( FNC_READ);
1758
    Imx_MT_Set_Buffer( device->ImxDevice, &imx_buf, FNC_READ);
1759
 
1760
    imx_buf.m_ptr = device->GetBuffer( FNC_WRITE);
1761
    Imx_MT_Set_Buffer( device->ImxDevice, &imx_buf, FNC_WRITE);
1762
 
1763
    imx_buf.m_ptr = device->GetBuffer( FNC_RECV);
1764
    Imx_MT_Set_Buffer( device->ImxDevice, &imx_buf, FNC_RECV);
1765
 
1766
    //temporary dataset, contents are copied with IMX functions and macros
1767
    IMXDS t_ds;
1768
 
1769
    //now process all the datasets of this device
1770
    for (int k = 0; k < device->GetDatasetCount(); k++)
1771
    {
1772
 
1773
      CDatasetObject *dataset = device->GetDataSet( k);
1774
 
1775
      //find duplicate dataset control tags
9 Marcel 1776
      for (unsigned long a = 0; a <= i; a++)
1 mjordaan 1777
      {
1778
 
1779
        CDeviceObject *dev = m_aDevice.GetAt( a);
1780
 
1781
        int c = a < i ? dev->GetDatasetCount() : k;
1782
 
1783
        for (int b = 0; b < c; b++)
1784
        {
1785
 
1786
          CDatasetObject *ds = dev->GetDataSet( b);
1787
 
1788
          if ((ds->DataSetTag.Id().t_type == dataset->DataSetTag.Id().t_type) &&
1789
              (ds->DataSetTag.Id().t_data == dataset->DataSetTag.Id().t_data))
1790
            ExitApplication( _T("IMX_UNIQUE"), dataset->GetName());
1791
        }
1792
      }
1793
 
1794
      memset( &t_ds, 0x00, sizeof( IMXDS));
1795
 
1796
      //io translator mailbox
1797
      Imx_Set_Snd_Mbx( &t_ds, dataset->IOxMailboxTag.Id());
1798
 
1799
      //datset control tag
1800
      Imx_Set_Ds_Ctrl( &t_ds, dataset->DataSetTag.Id());
1801
 
1802
      //name of the datset control tag
1803
      Imx_Set_Name( &t_ds, dataset->GetName());
1804
 
1805
      //additional dataset information
1806
      Imx_Set_Udata_Ptr( &t_ds, dataset);
1807
 
1808
      //set registration buffer
1809
      Imx_Set_R_Buffer( &t_ds, device->GetRegistrationBuffer());
1810
      Imx_Set_T_Buffer( &t_ds, device->GetRegistrationBuffer());
1811
 
1812
      //dataset information which does not depend on the message type
1813
      Imx_Set_Bnd_Dir( &t_ds, IMX_LOW_2_HIGH);
1814
      Imx_Set_Bit_Dir( &t_ds, IMX_LOW_2_HIGH);
1815
 
1816
      //start and length of the dataset
1817
      Imx_Set_Start( &t_ds, dataset->GetStart());
1818
 
1819
      switch (dataset->GetType())
1820
      {
1821
 
1822
        case DS_COMMAND_BOOL:
1823
        case DS_PARAMETER_BOOL: 
1824
        case DS_STATUS_BOOL: 
1825
        case DS_STATINFO_BOOL: 
1826
        case DS_STATDEL_BOOL:   Imx_Set_Boundary( &t_ds, IMX_BYTE_BND);
1827
                                Imx_Set_Len( &t_ds, dataset->GetLength());
1828
                                break;
1829
 
1830
        case DS_COMMAND_CHAR:
1831
        case DS_PARAMETER_CHAR: 
1832
        case DS_STATUS_CHAR:
1833
        case DS_STATINFO_CHAR: 
1834
        case DS_STATDEL_CHAR:   Imx_Set_Boundary( &t_ds, IMX_LONG_BND);
1835
                                Imx_Set_Bnd_Dir( &t_ds, IMX_HIGH_2_LOW);
1836
                                Imx_Set_Bit_Dir( &t_ds, IMX_HIGH_2_LOW);
1837
                                //every string is 20 characters
1838
                                Imx_Set_Len( &t_ds, dataset->GetLength() * PROT_STRING_SIZE/IMX_LONG_BND);
1839
                                Imx_Set_Start( &t_ds, dataset->GetStart() * PROT_STRING_SIZE/IMX_LONG_BND);
1840
                                break;
1841
 
1842
        case DS_EXCEPTION:      Imx_Set_Boundary( &t_ds, IMX_BYTE_BND);
1843
                                Imx_Set_Len( &t_ds, ImBasGetExceptionLength());
1844
                                break;
1845
 
1846
        case DS_COMMAND_INT:
1847
        case DS_PARAMETER_INT:  
1848
        case DS_STATUS_INT: 
1849
        case DS_STATINFO_INT: 
1850
        case DS_STATDEL_INT:    Imx_Set_Boundary( &t_ds, IMX_WORD_BND);
1851
                                Imx_Set_Len( &t_ds, dataset->GetLength());
1852
                                break;
1853
 
1854
        case DS_COMMAND_LONG:
1855
        case DS_PARAMETER_LONG:  
1856
        case DS_STATUS_LONG: 
1857
        case DS_STATINFO_LONG: 
1858
        case DS_STATDEL_LONG:   Imx_Set_Boundary( &t_ds, IMX_LONG_BND);
1859
                                Imx_Set_Len( &t_ds, dataset->GetLength());
1860
                                break;
1861
 
1862
        case DS_COMMAND_REAL:
1863
        case DS_PARAMETER_REAL:  
1864
        case DS_STATUS_REAL: 
1865
        case DS_STATINFO_REAL: 
1866
        case DS_STATDEL_REAL:   Imx_Set_Boundary( &t_ds, IMX_DBL_BND);
1867
                                Imx_Set_Len( &t_ds, dataset->GetLength());
1868
                                break;
1869
 
1870
        default:                Imx_Set_Boundary( &t_ds, IMX_BYTE_BND); 
1871
                                Imx_Set_Len( &t_ds, dataset->GetLength());
1872
                                break;
1873
      }
1874
 
1875
      //bit offset
1876
      Imx_Set_Bit_Offset( &t_ds, 0);
1877
 
1878
      //finally register the dataset with the imx library
1879
      IMXDS *ImxDataset = Imx_MT_Ds_Register( &t_ds, device->ImxDevice);
1880
 
1881
      if (ImxDataset == NULL) 
1882
        ExitApplication( _T("IMX_REGISTER"), dataset->GetName());
1883
 
1884
      //save the imx-dataset
1885
      dataset->SetImxDataset( ImxDataset);
1886
    }
1887
 
1888
    //create IMX threads
1889
    Imx_MT_CreateThread( device->ImxDevice);
1890
  }
1891
 
1892
  TAG *imx_tag = NULL;
1893
  void **imx_data;
1894
  unsigned long imx_num;
1895
  int (**imx_fnc)( void *, VAL);
1896
 
1897
  //add imx events to our event list
1898
  Imx_Event_Retrieve( &imx_tag, &imx_data, &imx_num, &imx_fnc);  
1899
 
1900
  //find the tag object, this a mailbox or dataset tag
1901
  //next add the event, with the imx event function
1902
  for (i = 0; i < imx_num; i++)
1903
  {
1904
 
1905
    //first check the mailbox tag
1906
    if ((imx_tag[ i].t_type == m_aDriver.GetAt( 0)->MailboxTag.Id().t_type) &&
1907
        (imx_tag[ i].t_data == m_aDriver.GetAt( 0)->MailboxTag.Id().t_data))
1908
    {
1909
 
1910
      //fill event data strucuture
1911
      m_aDriver.GetAt( 0)->SetImxData( *imx_fnc[ i], imx_data[ i]);
1912
 
1913
      //add event
1914
      SetEvent( m_aDriver.GetAt( 0)->MailboxTag, 
1915
                ImxEvent, 
1916
                m_aDriver.GetAt( 0)->GetImxData());
1917
    }
1918
    else
1919
    {
1920
 
1921
      for( int k = 0; k < m_aDevice.GetSize(); k++)
1922
        for( int m = 0; m < m_aDevice.GetAt( k)->GetDatasetCount(); m++)
1923
        {
1924
 
1925
          CDatasetObject *dataset = m_aDevice.GetAt( k)->GetDataSet( m);
1926
 
1927
          if ((imx_tag[ i].t_type == dataset->DataSetTag.Id().t_type) &&
1928
              (imx_tag[ i].t_data == dataset->DataSetTag.Id().t_data))
1929
          {
1930
 
1931
            //fill event data strucuture
1932
            dataset->SetImxData( *imx_fnc[ i], imx_data[ i]);
1933
 
1934
            //add event
1935
            SetEvent( dataset->DataSetTag, ImxEvent, dataset->GetImxData());
1936
          }
1937
        }
1938
    }
1939
  }
1940
 
1941
  //start listen thread for accepting connection requests
1942
  //start a thread, on completion we have the value to return to FL
1943
  if (m_ListenThread == NULL)
1944
  {
1945
 
1946
    //listen thread is only started if a driver is defined
1947
    if (m_aDriver.GetSize())
1948
    {
1949
 
1950
      m_ListenThread = new CWinThread( MyListenThread, (void *)m_aDriver.GetAt(0));
1951
      m_ListenThread->m_bAutoDelete = FALSE;
1952
 
1953
      //start the thread
1954
      m_ListenThread->CreateThread();
1955
    }
1956
  }
1957
}
1958
 
1959
 
1960
//////////////////////////////////////////////////////////////////////
1961
// void MyFlTask::Stopping()
1962
// 
1963
// 
1964
//////////////////////////////////////////////////////////////////////
1965
void MyFlTask::Stopping()
1966
{
8 mjordaan 1967
  int i;
1 mjordaan 1968
 
1969
  CodeTrace( _T("CANC_LIST"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0);
1970
 
1971
  //wait for the listen thread to end
1972
  CancelListening();
1973
 
1974
  //wait until all receive threads have ended
1975
  CodeTrace( _T("CANC_RECV"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0);
1976
  CancelReceiving();
1977
 
1978
  //Exit IMX MT library
1979
  Imx_MT_Exit();
1980
 
1981
  //destroy any remaining thread
8 mjordaan 1982
  for (i = 0; i < m_aDevice.GetSize(); i++)
1 mjordaan 1983
  {
1984
 
1985
    CDeviceObject *device = m_aDevice.GetAt( i);
1986
 
1987
 
1988
    Imx_MT_KillThreads( device->ImxDevice);
1989
  }
1990
 
1991
  //walk through the driver list and delete the objects, currently there is only one
1992
  for (i = 0; i < m_aDriver.GetSize(); i++)
1993
    delete m_aDriver.ElementAt( i);
1994
 
1995
  //clear the driver list
1996
  m_aDriver.RemoveAll();
1997
 
1998
  //walk through the device list and delete the datasets
1999
  for (i = 0; i < m_aDevice.GetSize(); i++)
2000
  {
2001
 
2002
    CDeviceObject *device = m_aDevice.ElementAt( i);
2003
 
2004
    device->RemoveAllDatasets();
2005
 
2006
    //release memory for IMX_DEVICE structure
2007
    free( device->ImxDevice);
2008
 
2009
    delete device;
2010
  }
2011
 
2012
  //clear the smtp list
2013
  m_aDevice.RemoveAll();
2014
 
2015
  //cleanup use of winsock stack
2016
  FlTask::WSACleanUp();
2017
 
2018
  //call original function
2019
  FlTask::Stopping();
2020
}
2021
 
2022
 
2023
/////////////////////////////////////////////////////////////////////////////
2024
// Descripton: In between checking for changed tags, which are input or 
2025
// triggers for the task, commands or jobs are inspected for completion.
2026
// 
2027
// Parameters: 
2028
// 
2029
// Returns: 
2030
// 
2031
// Comment: 
2032
// 
2033
/////////////////////////////////////////////////////////////////////////////
2034
void MyFlTask::Polling()
2035
{
2036
 
2037
 
2038
  //call the original one, it does some sleeping...
2039
  FlTask::Polling();
2040
}
2041
 
2042
 
2043
 
2044
/////////////////////////////////////////////////////////////////////////////
2045
// Descripton: Calling this function will send a stop request to the thread, 
2046
// which is listening for connection requests from BAS control subsystems.
2047
// The function will block untill the thread has ended.
2048
// 
2049
// Parameters: 
2050
// 
2051
// Returns: 
2052
// 
2053
// Comment: 
2054
// 
2055
/////////////////////////////////////////////////////////////////////////////
2056
void MyFlTask::CancelListening()
2057
{
2058
 
2059
 
2060
  DWORD exitcode = STILL_ACTIVE;
2061
  int Remaining = MAX_THREAD_STOPTIME;
2062
  long mysleep = 10;
2063
 
2064
 
2065
  //wait until the thread ends
2066
  while (m_ListenThread)
2067
  {
2068
 
2069
    //cancel the listen thread, done by closing the listen socket
2070
    CDriverObject *driver = m_aDriver.GetAt( 0);
2071
 
2072
    //tell thread to stop
2073
    m_bStopListening = true;
2074
 
2075
    //close the listen socket
2076
    if (driver->GetListenSocket() != INVALID_SOCKET)
2077
      driver->CloseListenSocket();
2078
 
2079
    if (!GetExitCodeThread( m_ListenThread->m_hThread, &exitcode))
2080
    {
2081
 
2082
      exitcode = 0; //error assume no exit code
2083
      int err = GetLastError();
2084
    }
2085
 
2086
    if (exitcode == STILL_ACTIVE)
2087
    {
2088
      FlSleep( mysleep); //thread active, wait and check again
2089
 
2090
      Remaining -= mysleep;
2091
 
2092
      //kill the thread if it is still running after waiting some time
2093
      if (Remaining <= 0)
2094
      {
2095
 
2096
        TerminateThread( m_ListenThread->m_hThread, -1);
2097
        //return;
2098
      }
2099
    }
2100
    else
2101
    {
2102
 
2103
      //thread has ended, release memory, destroy thread
2104
      delete m_ListenThread;
2105
      m_ListenThread = NULL;
2106
    }
2107
  }
2108
} //CancelListening
2109
 
2110
 
2111
/////////////////////////////////////////////////////////////////////////////
2112
// Descripton: Perform a read operation on the device for the specified
2113
// dataset. After reading the data, the result being data or an error code is 
2114
// sent to the IO-xlator task.
2115
// 
2116
// Parameters: ds - The IMX dataset for which a read operation is performed.
2117
// 
2118
// Returns: 
2119
// 
2120
// Comment: 
2121
// 
2122
/////////////////////////////////////////////////////////////////////////////
2123
void CDeviceObject::Read( IMXDS *ds)
2124
{
2125
 
2126
 
2127
  //the read can only be successfull if there is already a connection with
2128
  //the remote device
2129
  if ((IsConnected() != DEVICE_CONNECTED) || ((int)ReadDisableTag) ||
2130
      ((int)GetDriver()->StandbyTag))
2131
  {
2132
 
2133
    CString Xlate = _T("DRIVER_STANDBY");
2134
    int error = ERR_DRIVER_STANDBY;
2135
 
2136
    if (IsConnected() != DEVICE_CONNECTED) //device not connected
2137
    {
2138
 
2139
     Xlate = _T("DEVICE_NOT_CONNECTED");
2140
     error = ERR_DEVICE_NOT_CONNECTED;
2141
    }
2142
 
2143
    if ((int)ReadDisableTag) //read functionality disabled
2144
    {
2145
 
2146
      Xlate = _T("DEVICE_READ_DISABLED");
2147
      error = ERR_DEVICE_READ_DISABLED;
2148
    }
2149
 
2150
    //send error response to the translator task
2151
    theTask->MyRunTimeManager( error, FLS_ERROR, (char *)((LPCTSTR)Xlate), 
2152
                               (char *)((LPCTSTR)GetName()));
2153
 
2154
    //Imx error response
2155
    theTask->ImxSendError( ds, FNC_READ, error, this);
2156
 
2157
    return;
2158
  }
2159
 
2160
  //there is a connection, and function is not disabled
2161
  //build TX-buffer for command, and send data to remote device
2162
  //save the dataset on the object
2163
  SetCurrentImxDataset( ds);
2164
 
2165
  char *data = Imx_Get_U_Buffer( ds);
2166
  CDatasetObject *dataset = (CDatasetObject *)Imx_Get_Udata_Ptr( ds);
2167
 
2168
  //code trace message
2169
  theTask->CodeTrace( _T("DEVICE_READ"), 3, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT,NULL, 0, 
2170
                      (char *)((LPCTSTR)GetName()), (char *)((LPCTSTR)dataset->GetName()));
2171
 
2172
  //ready to send request to device, mark device waiting for read response
2173
  SetCmdPending( FNC_READ, 1);
2174
 
2175
  //send the message
2176
  if (int error = theTask->ImBasSendMessage( this, data, dataset->GetType()))
2177
  {
2178
 
2179
    //release read request
2180
    SetCmdPending( FNC_READ, 0);
2181
 
2182
    //sending failed, send error and completion to IOX
2183
    theTask->MyRunTimeManager( error, FLS_ERROR, _T("DEVICE_READ_ERROR"), (char *)((LPCTSTR)GetName()), 
2184
                               (char *)((LPCTSTR)dataset->GetName()), error);
2185
 
2186
    //Imx error response
2187
    theTask->ImxSendError( ds, FNC_READ, error, this);
2188
  }
2189
  else //wait for the recieve thread if there are no send errors
2190
  {
2191
 
2192
    //wait for read to complete
2193
    if (GetCmdPending( FNC_READ, theTask->GetResponseTimeout()))
2194
    {
2195
        //waited to long, give erro message
2196
        theTask->MyRunTimeManager( ERR_TIMEOUT, FLS_ERROR, _T("DEVICE_READ_ERROR"), 
2197
                                   (char *)((LPCTSTR)GetName()), 
2198
                                   (char *)((LPCTSTR)dataset->GetName()), ERR_TIMEOUT);
2199
 
2200
        //Imx error response
2201
        theTask->ImxSendError( ds, FNC_READ, ERR_TIMEOUT, this);
2202
        if (this) this->SetProtocolError( 0);
2203
 
2204
        //preserve imx dataset
2205
        LockImxDataset();
2206
 
2207
        //release read request
2208
        SetCmdPending( FNC_READ, 0);
2209
 
2210
        //release lock on imx dataset
2211
        ReleaseImxDataset();
2212
    }
2213
  }
2214
} //Read
2215
 
2216
 
2217
/////////////////////////////////////////////////////////////////////////////
2218
// Descripton: Perform a write operation on the device for the specified
2219
// dataset. After writing the data, the result success or an error code is 
2220
// sent to the IO-xlator task.
2221
// 
2222
// Parameters: ds - The IMX dataset for which a write operation is performed.
2223
// 
2224
// Returns: 
2225
// 
2226
// Comment: 
2227
// 
2228
/////////////////////////////////////////////////////////////////////////////
2229
void CDeviceObject::Write( IMXDS *ds)
2230
{
2231
 
2232
  //the write can only be successfull if there is already a connection with
2233
  //the remote device
2234
  if ((IsConnected() != DEVICE_CONNECTED) || ((int)ReadDisableTag) ||
2235
      ((int)GetDriver()->StandbyTag))
2236
  {
2237
 
2238
    CString Xlate = _T("DRIVER_STANDBY");
2239
    int error = ERR_DRIVER_STANDBY;
2240
 
2241
    if (IsConnected() != DEVICE_CONNECTED) //device not connected
2242
    {
2243
 
2244
     Xlate = _T("DEVICE_NOT_CONNECTED");
2245
     error = ERR_DEVICE_NOT_CONNECTED;
2246
    }
2247
 
2248
    if ((int)ReadDisableTag) //read functionality disabled
2249
    {
2250
 
2251
      Xlate = _T("DEVICE_READ_DISABLED");
2252
      error = ERR_DEVICE_READ_DISABLED;
2253
    }
2254
 
2255
    //send error response to the translator task
2256
    theTask->MyRunTimeManager( error, FLS_ERROR, (char *)((LPCTSTR)Xlate), 
2257
                               (char *)((LPCTSTR)GetName()));
2258
 
2259
    //Imx error response
2260
    theTask->ImxSendError( ds, FNC_WRITE, error, this);
2261
    return;
2262
  }
2263
 
2264
  //there is a connection, and function is not disabled
2265
  //build TX-buffer for command, and send data to remote device
2266
  //save the dataset on the object
2267
  SetCurrentImxDataset( ds);
2268
 
2269
  char *data = Imx_Get_U_Buffer( ds);
2270
  CDatasetObject *dataset = (CDatasetObject *)Imx_Get_Udata_Ptr( ds);
2271
 
2272
  if (Imx_Get_Handling( ds) == IMX_NORMAL_WRITE)
2273
  {
2274
 
2275
    //first try to minimalize the boundary of the element to be written
2276
    int fail = Imx_Ds_Evaluate_Write( ds);
2277
 
2278
    if ((fail != GOOD) && (fail != IMX_BLOCK) && (fail != IMX_X_WRITE))
2279
    {
2280
 
2281
      //send error response to the translator task
2282
      theTask->MyRunTimeManager( fail, FLS_ERROR, _T("DEVICE_WRITE_ERROR"), 
2283
                                 (char *)((LPCTSTR)GetName()), 
2284
                                 (char *)((LPCTSTR)dataset->GetName()), fail);
2285
 
2286
      //Imx error response
2287
      theTask->ImxSendError( ds, FNC_WRITE, fail, this);
2288
      return;
2289
    }
2290
    int mytest = Imx_Get_CDE( ds);
2291
    if (Imx_Get_CDE( ds) != CDE_BLOCK)
2292
    {
2293
 
2294
      //exception write < boundary: not supported
2295
      //send error response to the translator task
2296
      theTask->MyRunTimeManager( ERR_EXCEPTION_WRITE, FLS_ERROR, _T("DEVICE_WRITE_ERROR"), 
2297
                                 (char *)((LPCTSTR)GetName()), 
2298
                                 (char *)((LPCTSTR)dataset->GetName()), ERR_EXCEPTION_WRITE);
2299
 
2300
      //Imx error response
2301
      theTask->ImxSendError( ds, FNC_WRITE, ERR_EXCEPTION_WRITE, this);
2302
      return;
2303
    }
2304
  }
2305
  else
2306
  {
2307
 
2308
    //encoded write is not supported
2309
    //send error response to the translator task
2310
    theTask->MyRunTimeManager( ERR_ENCODED_WRITE, FLS_ERROR, _T("DEVICE_WRITE_ERROR"), 
2311
                               (char *)((LPCTSTR)GetName()), 
2312
                               (char *)((LPCTSTR)dataset->GetName()), ERR_ENCODED_WRITE);
2313
 
2314
    //Imx error response
2315
    theTask->ImxSendError( ds, FNC_WRITE, ERR_ENCODED_WRITE, this);
2316
    return;
2317
  }
2318
 
2319
  //normal block write, code trace message
2320
  theTask->CodeTrace( _T("DEVICE_WRITE"), 3, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT,NULL, 0, 
2321
                      (char *)((LPCTSTR)GetName()), (char *)((LPCTSTR)dataset->GetName()));
2322
 
2323
  int corr = (dataset->GetType() % 10 == 4) ? 5 : 1;
2324
  int maxorg = corr * (dataset->GetStart() + dataset->GetLength());
2325
  int maxds = Imx_Get_Start( ds) + Imx_Get_Len( ds);
2326
  int startorg = corr * dataset->GetStart();
2327
  int startds = Imx_Get_Start( ds);
2328
 
2329
  //check if addressing is in range with dataset definition
2330
  if ((maxds > maxorg) || (startds < startorg))
2331
  {
2332
 
2333
    //send error response to the translator task
2334
    theTask->MyRunTimeManager( ERR_BW_ADDRESS, FLS_ERROR, _T("DEVICE_WRITE_ERROR"), 
2335
                               (char *)((LPCTSTR)GetName()), 
2336
                               (char *)((LPCTSTR)dataset->GetName()), ERR_BW_ADDRESS);
2337
 
2338
    //Imx error response
2339
    theTask->ImxSendError( ds, FNC_WRITE, ERR_BW_ADDRESS, this);
2340
    return;
2341
  }
2342
 
2343
  //request send to device with suxccess, mark device for reading
2344
  SetCmdPending( FNC_WRITE, 1);
2345
 
2346
  //send the message
2347
  if (int error = theTask->ImBasSendMessage( this, data, dataset->GetType() + 100))
2348
  {
2349
 
2350
    //release read request
2351
    SetCmdPending( FNC_WRITE, 0);
2352
 
2353
    //sending failed, send error and completion to IOX
2354
    theTask->MyRunTimeManager( error, FLS_ERROR, _T("DEVICE_WRITE_ERROR"), (char *)((LPCTSTR)GetName()), 
2355
                               (char *)((LPCTSTR)dataset->GetName()), error);
2356
 
2357
    //Imx error response
2358
    theTask->ImxSendError( ds, FNC_WRITE, error, this);
2359
  }
2360
  else
2361
  {
2362
 
2363
    //wait for read to complete
2364
    if (GetCmdPending( FNC_WRITE, theTask->GetResponseTimeout()))
2365
    {
2366
        //waited to long, give error message
2367
        theTask->MyRunTimeManager( ERR_TIMEOUT, FLS_ERROR, _T("DEVICE_WRITE_ERROR"), 
2368
                                 GetName(), 
2369
                                 dataset->GetName(), 
2370
                                 ERR_TIMEOUT);
2371
 
2372
        //Imx error response
2373
        theTask->ImxSendError( ds, FNC_WRITE, ERR_TIMEOUT, this);
2374
        if (this) this->SetProtocolError( 0);
2375
 
2376
        //preserve imx dataset
2377
        LockImxDataset();
2378
 
2379
        //release read request
2380
        SetCmdPending( FNC_WRITE, 0);
2381
 
2382
        //release lock on imx dataset
2383
        ReleaseImxDataset();
2384
    }
2385
  }
2386
} //Write
2387
 
2388
 
2389
/////////////////////////////////////////////////////////////////////////////
2390
// Descripton: Create a listen socket for the driver, all connections are 
2391
// accepted on this socket. The creation of the socket includes the following:
2392
// socket creation for TCP/IP, setting the options for shutdown
2393
// 
2394
// Parameters: 
2395
// 
2396
// Returns: The function returns an error (not equal to zero) or success as 
2397
// a zero value.
2398
// 
2399
// Comment: 
2400
// 
2401
/////////////////////////////////////////////////////////////////////////////
2402
int CDriverObject::CreateListenSocket()
2403
{
2404
 
2405
  //if there is a socket return without an error
2406
  if (m_sListen != INVALID_SOCKET) closesocket( m_sListen);
2407
 
2408
  //open the listen socket
2409
  if ((m_sListen = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
2410
    return ERR_SOCKET_CREATION; //return error code
2411
  else //set the options we need
2412
  {
2413
 
2414
    struct linger lng;
2415
 
2416
    //turn linger on, but without timeout
2417
    lng.l_onoff = true;
2418
    lng.l_linger = 0;
2419
 
2420
    setsockopt( m_sListen, SOL_SOCKET, SO_LINGER, (char *)&lng, sizeof( struct linger));
2421
 
2422
    //socket is in blocking mode
2423
    ioctlsocket( m_sListen, FIONBIO, NULL);
2424
  }
2425
 
2426
  //success
2427
  return 0;
2428
}
2429
 
2430
 
2431
/////////////////////////////////////////////////////////////////////////////
2432
// Descripton: Check the given message for protocol errors, message up to the 
2433
// given length is check for errors.
2434
// 
2435
// Parameters: *buffer - Buffer in which the received data si stored, this data
2436
// is checked for protocol errors.
2437
// MsgLength - The full lenght of th emessage, or the length of the buffer to 
2438
// check for protocol errors.
2439
// MsgType - The message type of the received data, the data is check if it con-
2440
// tains the same message type identification.
2441
//
2442
// Returns: If there are no protocol errors found in 'buffer' zero is returned, 
2443
// otherwise an error code is returned.
2444
// 
2445
// Comment: 
2446
// 
2447
/////////////////////////////////////////////////////////////////////////////
2448
int MyFlTask::ImBasCheckRxBuffer(char *buffer, int MsgLength, int MsgType)
2449
{
2450
 
2451
  //first the fixed items are checked, it is assumed that we are
2452
  //dealing with an incoming message
2453
 
2454
  if (MsgLength < 2) return 0;
2455
 
2456
  //source field in header
2457
  //if ((buffer[ 0] != 'B') || (buffer[ 1] != 'C')) return ERR_INVALID_SOURCE;
2458
  if ((buffer[ 0] != m_sDestination[ 0]) || (buffer[ 1] != m_sDestination[ 1])) return ERR_INVALID_SOURCE;
2459
 
2460
  if (MsgLength < 4) return 0;
2461
 
2462
  //destination field in header
2463
  //if ((buffer[ 2] != 'I') || (buffer[ 3] != 'M')) return ERR_INVALID_DESTINATION;
2464
  if ((buffer[ 2] != m_sSource[ 0]) || (buffer[ 3] != m_sSource[ 1])) return ERR_INVALID_DESTINATION;
2465
 
2466
  if (MsgLength < 6) return 0;
2467
 
2468
/*
2469
  m_sIdLifeSign = _T("00");     //00
2470
  m_sIdCommand = _T("01");      //01
2471
  m_sIdParameter = _T("02");    //02
2472
  m_sIdSetParameter = _T("03"); //03
2473
  m_sIdStatus = _T("11");       //11
2474
  m_sIdStatistical = _T("12");  //12
2475
  m_sIdException = _T("21");    //21
2476
*/
2477
 
2478
  //find the data length of the message
2479
  int len = ImBasGetDataLength( buffer, MsgLength);
2480
  int dlen;
2481
  int i;
2482
 
2483
  //message types
2484
  switch (MsgType)
2485
  {
2486
 
2487
    case DS_COMMAND_BOOL:
2488
    case DS_COMMAND_INT:
2489
    case DS_COMMAND_LONG:
2490
    case DS_COMMAND_REAL:
2491
    case DS_COMMAND_CHAR:
2492
      if ((buffer[ 4] != m_sIdCommand[ 0]) || (buffer[ 5] != m_sIdCommand[ 1])) 
2493
        return ERR_INVALID_TYPE;  
2494
      break;
2495
 
2496
    case DS_PARAMETER_BOOL:
2497
    case DS_PARAMETER_INT:
2498
    case DS_PARAMETER_LONG:
2499
    case DS_PARAMETER_REAL:
2500
    case DS_PARAMETER_CHAR:
2501
      if ((buffer[ 4] != m_sIdParameter[ 0]) || ((buffer[ 5] != m_sIdParameter[ 1]) && (buffer[ 5] != m_sIdSetParameter[ 1]))) 
2502
        return ERR_INVALID_TYPE;  
2503
      break;
2504
 
2505
    case DS_STATUS_BOOL:
2506
    case DS_STATUS_INT:
2507
    case DS_STATUS_LONG:
2508
    case DS_STATUS_REAL:
2509
    case DS_STATUS_CHAR:
2510
      if ((buffer[ 4] != m_sIdStatus[ 0]) || (buffer[ 5] != m_sIdStatus[ 1])) 
2511
        return ERR_INVALID_TYPE;
2512
      break;
2513
 
2514
    case DS_STATINFO_BOOL:
2515
    case DS_STATDEL_BOOL:
2516
    case DS_STATINFO_INT:
2517
    case DS_STATDEL_INT:
2518
    case DS_STATINFO_LONG:
2519
    case DS_STATDEL_LONG:
2520
    case DS_STATINFO_REAL:
2521
    case DS_STATDEL_REAL:
2522
    case DS_STATINFO_CHAR:
2523
    case DS_STATDEL_CHAR:
2524
      if ((buffer[ 4] != m_sIdStatistical[ 0]) || (buffer[ 5] != m_sIdStatistical[ 1]))
2525
        return ERR_INVALID_TYPE;  
2526
      break;
2527
 
2528
    case DS_EXCEPTION:
2529
      if ((buffer[ 4] != m_sIdException[ 0]) || (buffer[ 5] != m_sIdException[ 1]))
2530
        return ERR_INVALID_TYPE;  
2531
 
2532
      //check the datalength
2533
      for ( i = 0, dlen = 0; i < 10; i++)
2534
        dlen += m_iExceptionSize[ i];
2535
      //invalid lifesign lengths are sometimes accepted, ndicating the max length 
2536
      //for the description is exceeded, but message is accepted.
2537
 
2538
      if ((len != dlen) && !m_iAcceptIllegalException) return ERR_DATA_LENGTH;
2539
      break;
2540
 
2541
    case DS_LIFESIGN:
2542
      if ((buffer[ 4] != m_sIdLifeSign[ 0]) || (buffer[ 5] != m_sIdLifeSign[ 1]))
2543
        return ERR_INVALID_TYPE;  
2544
      break;
2545
 
2546
    default: return ERR_INVALID_TYPE;
2547
  }
2548
 
2549
  if (MsgLength < 8) return 0;
2550
 
2551
  //version number
2552
  if (strncmp( &buffer[ 6], (LPCTSTR)m_sProtocolVersion, 2))
2553
    return ERR_INVALID_VERSION;
2554
 
2555
  if (MsgLength < 10) return 0;
2556
 
2557
  //check sequence number
2558
  if (MsgType == DS_LIFESIGN)
2559
  {
2560
 
2561
    if ((buffer[ 8] != '0') || (buffer[ 9] != '0'))
2562
      return ERR_INVALID_SEQUENCE;  
2563
  }
2564
 
2565
  if ((len >= 0) && (MsgLength > (len + PROT_HEADER_LEN)))
2566
  {
2567
 
2568
    if (buffer[ len + PROT_HEADER_LEN] != ImBasGetTerminator())
2569
      return ERR_INVALID_TERMINATOR;
2570
  }
2571
 
2572
  return 0;
2573
}
2574
 
2575
 
2576
/////////////////////////////////////////////////////////////////////////////
2577
// Descripton: Retrieve the datalength from the data buffer
2578
// 
2579
// Parameters: 
2580
// 
2581
// Returns: 
2582
// 
2583
// Comment: 
2584
// 
2585
/////////////////////////////////////////////////////////////////////////////
2586
int MyFlTask::ImBasGetDataLength( char *buf, int length)
2587
{
2588
 
2589
  //if length data is not included in buffer return negtive
2590
  if (length < 13) return -1;
2591
 
2592
  //get length
2593
  CString len = _T("000");
2594
  len.SetAt( 0, buf[ 10]);
2595
  len.SetAt( 1, buf[ 11]);
2596
  len.SetAt( 2, buf[ 12]);
2597
 
2598
  return atoi( len);
2599
}
2600
 
2601
/////////////////////////////////////////////////////////////////////////////
2602
// Descripton: Retrieve the datalength from the data buffer
2603
// 
2604
// Parameters: 
2605
// 
2606
// Returns: 
2607
// 
2608
// Comment: 
2609
// 
2610
/////////////////////////////////////////////////////////////////////////////
2611
int MyFlTask::ImBasGetDataCount( char *buf, int length)
2612
{
2613
  int i  = 1;
2614
  //if length data is not included in buffer return negtive
2615
  if (length < 18) return -1;
2616
 
2617
  //get length
2618
  CString len = _T("00");
2619
  len.SetAt( 0, buf[ 16]);
2620
  len.SetAt( 1, buf[ 17]);
2621
 
2622
  if (buf[15] == 'S') i = 5;
2623
  return (i * atoi( len));
2624
} //ImBasGetDataCount
2625
 
2626
 
2627
/////////////////////////////////////////////////////////////////////////////
2628
// Descripton: Retrieve the datalength from the data buffer
2629
// 
2630
// Parameters: 
2631
// 
2632
// Returns: 
2633
// 
2634
// Comment: 
2635
// 
2636
/////////////////////////////////////////////////////////////////////////////
2637
int MyFlTask::ImBasGetSequence( char *buf, int length)
2638
{
2639
 
2640
  //if length data is not included in buffer return negtive
2641
  if (length < 10) return -1;
2642
 
2643
  //get length
2644
  CString len = _T("00");
2645
  len.SetAt( 0, buf[ 8]);
2646
  len.SetAt( 1, buf[ 9]);
2647
 
2648
  return atoi( len);
2649
}
2650
 
2651
 
2652
/////////////////////////////////////////////////////////////////////////////
2653
// Description: Retrieve the message type from the data buffer
2654
// 
2655
// Parameter: *buf - Character buffer in which th emessage is received.
2656
// Parameter: length - Length of the character buffer 'buf'.
2657
// 
2658
// Returns: The type of the message as an integer, note that the value is derived
2659
// from the received message and therefor only the base (or default) type of the 
2660
// message is returned. These types are only the boolean data types for the message.
2661
// 
2662
// Comment: 
2663
//
2664
/////////////////////////////////////////////////////////////////////////////
2665
int MyFlTask::ImBasGetType( char *buf, int length)
2666
{
2667
 
2668
  //if length data is not included in buffer return negtive
2669
  if (length < 6) return -1;
2670
 
2671
  //get type
2672
  CString type = _T("00");
2673
  type.SetAt( 0, buf[ 4]);
2674
  type.SetAt( 1, buf[ 5]);
2675
 
2676
  switch (atoi( type))
2677
  {
2678
 
2679
    case  0: return DS_LIFESIGN;       //life sign
2680
    case  1: return DS_COMMAND_BOOL;   //command
2681
    case  2: return DS_PARAMETER_BOOL; //parameter data
2682
    case  3: return DS_PARAMETER_BOOL; //parameter data
2683
    case 11: return DS_STATUS_BOOL;    //status 
2684
    case 12: return DS_STATINFO_BOOL;  //statistical info
2685
    case 21: return DS_EXCEPTION;      //exception
2686
    default: break;
2687
  }
2688
 
2689
  return -1; //return invalid message type
2690
}
2691
 
2692
 
2693
/////////////////////////////////////////////////////////////////////////////
2694
// Description: Retrieve the message type from the data buffer
2695
// 
2696
// Parameter: *buf - Character buffer in which th emessage is received.
2697
// Parameter: length - Length of the character buffer 'buf'.
2698
// 
2699
// Returns: The data as a character, the format is the sdame as in the IM-BAS
2700
// protocol, 'B" for boolean, 'I' for integer, 'L' for long, 'R' for float and
2701
// 'S' for string.
2702
// 
2703
// Comment: 
2704
//
2705
/////////////////////////////////////////////////////////////////////////////
2706
char MyFlTask::ImBasGetDataType( char *buf, int length)
2707
{
2708
 
2709
  //if length data is not included in buffer return negtive
2710
  if (length < PROT_HEADER_LEN+1) return -1;
2711
 
2712
  //get datatype
2713
  return buf[ 15];
2714
} //ImBasGetDataType
2715
 
2716
 
2717
/////////////////////////////////////////////////////////////////////////////
2718
// Descripton: Retrieve system id form data buffer
2719
// 
2720
// Parameters: 
2721
// 
2722
// Returns: 
2723
// 
2724
// Comment: 
2725
// 
2726
/////////////////////////////////////////////////////////////////////////////
2727
CString MyFlTask::ImBasGetSystemId( char *buf, int length)
2728
{
2729
 
2730
  CString id = _T("  ");
2731
 
2732
 
2733
  //if id is not included in buffer return empty string
2734
  if (length < 15) return id;
2735
 
2736
  //get length
2737
  id.SetAt( 0, buf[ 13]);
2738
  id.SetAt( 1, buf[ 14]);
2739
 
2740
  return id;
2741
}
2742
 
2743
/////////////////////////////////////////////////////////////////////////////
2744
// Descripton: Receive a message on the specified socket. Receiving a message 
2745
// starts with receiving a header of 15 bytes, if the strucutur of these 15 
2746
// bytes is recognized as a header, the additional data is read followed by 
2747
// the message terminator
2748
// 
2749
// Parameters: sock - the socket for which a message will be received.
2750
// buffer - Character buffer, define dby the caller, to hold the complete
2751
// message, including header and terminator.
2752
// type - Ouput parameter, in case a message is received this parameter is
2753
// filled with message type. The parameter is an integer pointer
2754
// 
2755
// Returns: The function returns with a message or an error code. The return
2756
// value is zero for success and is the error number if there is a failure.
2757
// a failure indicates an error on Winsock level, the receive failed. Normally
2758
// this is caused by the remote partner who closed the connection, or an in-
2759
// ternal stop request, which caused the socket to close.
2760
// 
2761
// Comment: 
2762
// 
2763
/////////////////////////////////////////////////////////////////////////////
2764
int MyFlTask::ImBasRecvMessage( SOCKET sock, char *buffer, int *type, 
2765
                                CDeviceObject *device)
2766
{
2767
 
2768
  int rlen = 0;
2769
  int error;
2770
  FD_SET rfds;
2771
  TIMEVAL t = { 0, 0};
2772
  TIMEVAL *tval = NULL;
2773
 
2774
  if (device)
2775
  {
2776
    //timeout value is configured response time, plus 20%
2777
    t.tv_sec = device->GetAliveTime() + (device->GetAliveTime() / 5);
2778
 
2779
    //error generation after the timeout is needed to notify the driver of
2780
    //communication loss, life signs are not received within the configured
2781
    //time period, so ther emust be already a connection before timeouts are 
2782
    //usefull
2783
    if (device->IsConnected() && device->theTask->UseLifesignTimeout()) tval = &t;
2784
  }
2785
  else
2786
  {
2787
 
2788
    //first lifesign, use default timeout
2789
    t.tv_sec = GetFirstLifeSign();
2790
 
2791
    tval = &t;
2792
  }
2793
 
2794
  //start receiving a header
2795
  while (rlen < PROT_HEADER_LEN)
2796
  {
2797
 
2798
    //wait for data
2799
    FD_ZERO( &rfds);
2800
    FD_SET( sock, &rfds);
2801
 
2802
    error = select( 0, &rfds, NULL, NULL, tval);
2803
 
2804
    if ((error == SOCKET_ERROR) || (error == 0))
2805
    {
2806
 
2807
      //timeout reached, update device status
2808
      if (error == 0)
2809
      {
2810
 
2811
        if (device)
2812
        {
2813
          //update status tag
2814
          device->UpdateStatus( ERR_LIFESIGN_TIMEOUT);
2815
 
2816
          //update connection tag
2817
          device->UpdateConnection( DEVICE_TCPIP_ONLY);
2818
 
2819
          //update runtime manager
2820
          MyRunTimeManager( ERR_LIFESIGN_TIMEOUT, FLS_ERROR, _T("LIFESIGN_TIMEOUT"), 
2821
                            device->GetName(), device->GetAliveTime());
2822
 
2823
          //exit or continue?
2824
          if (device->theTask->DisconnectLifesignLoss()) return ERR_RX_FAILED;
2825
          else continue;
2826
        }
2827
        else
2828
        {
2829
 
2830
          //update runtime manager
2831
          MyRunTimeManager( ERR_LIFESIGN_TIMEOUT, FLS_ERROR, _T("LIFESIGN_TIMEOUT"), 
2832
                            Xlate("UNKNOWN_DEV"), t.tv_sec);
2833
          //first timeout, no device return with RX error
2834
          return ERR_RX_FAILED;
2835
        }
2836
      }
2837
 
2838
      //trace the winsock error
2839
      if ((error == SOCKET_ERROR) && device)
2840
        CodeTrace( _T("SOCKET_ERROR"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, 
2841
                   WSAGetLastError(), device->GetName());
2842
 
2843
      return ERR_RX_FAILED; //read error
2844
    }
2845
 
2846
    //check for stop condition
2847
    if (Imx_MT_Get_Stop()) return ERR_RX_FAILED;
2848
 
2849
    //inhibit send actions
2850
    if (device) device->Lock();
2851
 
2852
    //receive the header
2853
    error = recv( sock, &buffer[ rlen], PROT_HEADER_LEN, 0);
2854
 
2855
    //release device for send actions
2856
    if (device) device->Release();
2857
 
2858
    //evaluate the received data
2859
    if (!error || (error == SOCKET_ERROR ))
2860
    {
2861
 
2862
      //build device name for logging purposes
2863
      CString DevName = (device) ? device->GetName() : Xlate( "UNKNOWN_DEV");
2864
 
2865
      if (!error)
2866
        CodeTrace( _T("SOCKET_CLOSED"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, DevName);
2867
      else
2868
        CodeTrace( _T("SOCKET_ERROR"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, WSAGetLastError(), DevName);
2869
 
2870
      return ERR_RX_FAILED;
2871
    }
2872
    else 
2873
      rlen += error; //number of received bytes
2874
  }
2875
 
2876
  //evaluate the header, assume header is ok and extract message type
2877
  *type = ImBasGetType( buffer, PROT_HEADER_LEN);
2878
 
2879
  //now check if everything is ok, including the expected message type
2880
  if (error = ImBasCheckRxBuffer( buffer, PROT_HEADER_LEN, *type))
2881
  {
2882
 
2883
    //code trace for invalid protocol data
2884
    CodeTrace( _T("DEVICE_INVRX"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, buffer, PROT_HEADER_LEN, error);
2885
 
2886
    //save protocol error on device
2887
    if (device) device->SetProtocolError( error);
2888
 
2889
    //read data untill terminator is received
2890
    int check = rlen > 0 ? rlen - 1: 0;
2891
    if (!rlen) buffer[ rlen] = '0';
2892
 
2893
    while (buffer[ check] != ImBasGetTerminator())
2894
    {
2895
 
2896
      //wait for data
2897
      FD_ZERO( &rfds);
2898
      FD_SET( sock, &rfds);
2899
      t.tv_sec = 0;
2900
      t.tv_usec = 0;
2901
      error = select( 0, &rfds, NULL, NULL, &t);
2902
 
2903
      if (!error || error == SOCKET_ERROR)
2904
      {
2905
 
2906
        //build device name for logging purposes
2907
        CString DevName = (device) ? device->GetName() : Xlate( "UNKNOWN_DEVID", ImBasGetSystemId( buffer, PROT_HEADER_LEN));
2908
 
2909
        //trace the winsock error
2910
        if (error == SOCKET_ERROR)
2911
          CodeTrace( _T("SOCKET_ERROR"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, WSAGetLastError());
2912
        else
2913
          CodeTrace( _T("RCV_TIMEOUT"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, DevName);
2914
 
2915
        break;
2916
      }
2917
 
2918
      recv( sock, &buffer[ rlen++], 1, 0);
2919
      check = rlen - 1;
2920
    } 
2921
 
2922
    //code trace for invalid protocol data
2923
    //if (rlen > 1)
2924
    //  CodeTrace( _T("DEVICE_INVRX"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, buffer, rlen-1, ERR_RECVLEN);
2925
 
2926
    rlen = 0; //invalid header, try again
2927
 
2928
    //give a value for message type: unknown type
2929
    *type = 0;
2930
    if (m_iDisconnectProtocolErrors) return ERR_RX_FAILED;
2931
    else return 0;
2932
  }
2933
 
2934
  //header is received and is looking fine, receive data
2935
  while (rlen < (PROT_HEADER_LEN + ImBasGetDataLength( buffer, PROT_HEADER_LEN) + 1))
2936
  {
2937
 
2938
    //wait for data
2939
    FD_ZERO( &rfds);
2940
    FD_SET( sock, &rfds);
2941
    select( 0, &rfds, NULL, NULL, &t);
2942
 
2943
    //receive data
2944
    error = recv( sock, &buffer[ rlen], PROT_HEADER_LEN + ImBasGetDataLength( buffer, PROT_HEADER_LEN) + 1 - rlen, 0);
2945
 
2946
    //evaluate the received data
2947
    if (!error || (error == SOCKET_ERROR ))
2948
    {
2949
 
2950
      //build device name for logging purposes
2951
      CString DevName = (device) ? device->GetName() : Xlate( "UNKNOWN_DEV");
2952
 
2953
      if (!error)
2954
        CodeTrace( _T("SOCKET_CLOSED"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, device->GetName());
2955
      else
2956
        CodeTrace( _T("SOCKET_ERROR"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, WSAGetLastError(), device->GetName());
2957
 
2958
      return ERR_RX_FAILED;
2959
    }
2960
    else 
2961
      rlen += error; //number of received bytes
2962
  }
2963
 
2964
  CodeTrace( _T("DEVICE_RX"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, buffer, rlen);
2965
 
2966
  //check received message, this time only for terminator...
2967
  if (error = ImBasCheckRxBuffer( buffer, rlen, *type))
2968
  {
2969
 
2970
    //save the protocol error on the device
2971
    if (device) device->SetProtocolError( error);
2972
 
2973
    //invalidate the message type
2974
    *type = 0;
2975
 
2976
    if (m_iDisconnectProtocolErrors) return error;
2977
  }
2978
 
2979
   //done, all data received
2980
   return 0;
2981
} //ImBasRecvMessage
2982
 
2983
 
2984
/////////////////////////////////////////////////////////////////////////////
2985
// Descripton: Send a message to the remote station
2986
// 
2987
// Parameters: 
2988
// 
2989
// Returns: 
2990
// 
2991
// Comment: 
2992
//calculate the maximum response size, split the request if the response 
2993
//exceeds the limit of 999 data byte
2994
//for (int x = 0; x < dataset->GetLength() / theTask->ImBasMaxLength( dataset->GetType()) + 1; x++)
2995
//;
2996
// 
2997
/////////////////////////////////////////////////////////////////////////////
2998
int MyFlTask::ImBasSendMessage( CDeviceObject *device, char *buffer, int type)
2999
{
3000
 
3001
  //calculate datalength for dataset and fill data buffer
3002
  int start = 0;
3003
  int length = 0;
3004
  char data[ IMX_BUFFER_SIZE];
3005
  int rep = 1;
3006
  int corr = 1; 
3007
 
3008
  //we need a device,if there is none don't send anything
3009
  if (!device) return ERR_TX_FAILED; //error code is general
3010
 
3011
  CodeTrace( _T("SEND_MESSAGE"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, device->GetName(), type);
3012
 
3013
  //correction factor for packet count
3014
  switch (type)
3015
  {
3016
 
3017
    case DS_COMMAND_CHAR:
3018
    case DS_PARAMETER_CHAR:
3019
    case DS_STATUS_CHAR:
3020
    case DS_STATINFO_CHAR:
3021
    case DS_STATDEL_CHAR: 
3022
    case DSW_COMMAND_CHAR:
3023
    case DSW_PARAMETER_CHAR:
3024
    case DSW_STATUS_CHAR:
3025
    case DSW_STATINFO_CHAR:
3026
    case DSW_STATDEL_CHAR:
3027
 
3028
    case DS_EXCEPTION:
3029
    case DSW_EXCEPTION: //response send, end of command
3030
 
3031
      //correction only needed if there is an active imx-dataset
3032
      if (device->GetCurrentImxDataset())
3033
      {
3034
 
3035
        //see if we need a correction factor fo the number of bytes to send
3036
        IMXDS *t = device->GetCurrentImxDataset();
3037
        corr = t->boundary;
3038
        corr = PROT_STRING_SIZE/Imx_Get_Boundary(device->GetCurrentImxDataset()); 
3039
        corr = PROT_STRING_SIZE/t->boundary;
3040
      }
3041
 
3042
    case DS_LIFESIGN:
3043
    case DSW_LIFESIGN:
3044
 
3045
    case DS_COMMAND_BOOL:
3046
    case DS_COMMAND_INT:
3047
    case DS_COMMAND_LONG:
3048
    case DS_COMMAND_REAL:
3049
    case DS_PARAMETER_BOOL:
3050
    case DS_PARAMETER_INT:
3051
    case DS_PARAMETER_LONG:
3052
    case DS_PARAMETER_REAL:
3053
    case DS_STATUS_BOOL:
3054
    case DS_STATUS_INT:
3055
    case DS_STATUS_LONG:
3056
    case DS_STATUS_REAL:
3057
    case DS_STATINFO_BOOL:
3058
    case DS_STATINFO_INT:
3059
    case DS_STATINFO_LONG:
3060
    case DS_STATINFO_REAL:
3061
    case DS_STATDEL_BOOL:
3062
    case DS_STATDEL_INT:
3063
    case DS_STATDEL_LONG:
3064
    case DS_STATDEL_REAL:
3065
 
3066
    case DSW_COMMAND_BOOL:
3067
    case DSW_COMMAND_INT:
3068
    case DSW_COMMAND_LONG:
3069
    case DSW_COMMAND_REAL:
3070
    case DSW_PARAMETER_BOOL:
3071
    case DSW_PARAMETER_INT:
3072
    case DSW_PARAMETER_LONG:
3073
    case DSW_PARAMETER_REAL:
3074
    case DSW_STATUS_BOOL:
3075
    case DSW_STATUS_INT:
3076
    case DSW_STATUS_LONG:
3077
    case DSW_STATUS_REAL:
3078
    case DSW_STATINFO_BOOL:
3079
    case DSW_STATINFO_INT:
3080
    case DSW_STATINFO_LONG:
3081
    case DSW_STATINFO_REAL:
3082
    case DSW_STATDEL_BOOL:
3083
    case DSW_STATDEL_INT:
3084
    case DSW_STATDEL_LONG:
3085
    case DSW_STATDEL_REAL:
3086
 
3087
    //case DSW_EXCEPTION: //response send, end of command
3088
      break;
3089
 
3090
    default:
3091
      //the command issued is unknown
3092
      return ERR_CMD_UNKNOWN;
3093
  }
3094
 
3095
  if (device->GetCurrentImxDataset())
3096
  {
3097
 
3098
    //data = buffer ? buffer: Imx_Get_U_Buffer( device->GetCurrentImxDataset());
3099
    rep = GetPacketCount( Imx_Get_Len( device->GetCurrentImxDataset()), type);
3100
 
3101
    CodeTrace( _T("REPETION_TX"), 5, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, 
3102
               rep, (char *)((LPCTSTR)device->GetName()));
3103
 
3104
  }
3105
  //else
3106
  //  data = new char[ IMX_BUFFER_SIZE];
3107
 
3108
  //memory allocation error
3109
//  if (!data) return ERR_MEMORY_ALLOCATION;
3110
 
3111
  if (rep < 1) rep = 1;
3112
 
3113
  //send all the message packets
3114
  for (int i = 0; i < rep; i++)
3115
  {
3116
 
3117
    if (device->GetCurrentImxDataset())
3118
    {
3119
 
3120
      int len = (Imx_Get_Len( device->GetCurrentImxDataset()) / corr) - (i * ImBasMaxLength( type));
3121
      len = len > ImBasMaxLength( type) ? ImBasMaxLength( type) : len;
3122
 
3123
      start = Imx_Get_Start( device->GetCurrentImxDataset()) / corr;
3124
      start += (i * ImBasMaxLength( type));
3125
      length = len;
3126
    }  
3127
 
3128
    //clear send buffer
3129
    memset( data, (int)' ', IMX_BUFFER_SIZE);
3130
 
3131
    //build data part of send buffer
3132
    int datalen = ImBasImx2Data( data, type, start, &length, device);
3133
 
3134
    //check for invalid type
3135
    if (datalen < 0)
3136
      return ERR_INVALID_ACTION;
3137
 
3138
    //build the buffer with data, start with the header
3139
    ImBasBuildHeader( data, device, &datalen, type);
3140
 
3141
    //datalength is updated with header length
3142
    datalen += PROT_LIFESIGN_MSG;
3143
 
3144
    //inhibit recv actions
3145
    CodeTrace( _T("SEND_LOCK"), 5, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, device->GetName());
3146
    device->Lock();
3147
 
3148
    //send the data
3149
    int slen = 0;
3150
    if (datalen != (slen = send( device->GetSocket(), data, datalen, 0)))
3151
    {
3152
 
3153
      CodeTrace( _T("DEVICE_TXLEN"), 5, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, 
3154
                 datalen, slen, (char *)((LPCTSTR)device->GetName()));
3155
 
3156
      //release device for recv actions
3157
      device->Release();
3158
 
3159
      //something went wrong, error code is general send error
3160
      return ERR_TX_FAILED;
3161
    }
3162
    else //code trace message
3163
    {
3164
 
3165
      CodeTrace( _T("DEVICE_TXLEN"), 5, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, 
3166
                 datalen, slen, (char *)((LPCTSTR)device->GetName()));
3167
      CodeTrace( _T("DEVICE_TX"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, data, datalen, 
3168
                         (char *)((LPCTSTR)device->GetName()));
3169
    }
3170
 
3171
    //release device for recv actions
3172
    device->Release();
3173
  }
3174
 
3175
  return 0;
3176
} //ImBasSendMessage
3177
 
3178
 
3179
/////////////////////////////////////////////////////////////////////////////
3180
// Descripton: Send an response to the translator, use our own defined task
3181
// id(s), overrule the one defined with imx.
3182
// This function check if the mailbox for sending messages has not more then 
3183
// the maximum allowed number of messages. The user is responsible for selecting
3184
// a maximum number of mbx messages, which will not overload the system (system
3185
// wide settings are set with command line options of the run-tiume manager 
3186
// task (-m option).
3187
// 
3188
// Parameters: 
3189
// *ds - Pointer to an IMXDS structure, which is the currently processed
3190
//       dataset.
3191
// Function - Integer specifying the type of the response for the IO-translator.
3192
//            The response type can be FNC_READ (0), FNC_WRITE (1) or FNC_RECV (2).
3193
// *dev - Pointer to the device object associated with the specified IMX dataset, see
3194
// the first parameter '*ds'.
3195
// SaveError - Integer parameter with value false (0) or true (any value except 0), 
3196
//             if the value is true any existing error condition on the task is saved
3197
//             and the task status remains red if there is a previous error, otherwise
3198
//             the task status will green, indicatin error free operation.
3199
// 
3200
// Returns: 
3201
// 
3202
// Comment: 
3203
// 
3204
/////////////////////////////////////////////////////////////////////////////
3205
void MyFlTask::ImxSend(IMXDS *ds, int Function, CDeviceObject *dev, int SaveError)
3206
{
3207
 
3208
  IMXSYSTEM imxsys;
3209
  int error = 0;
3210
 
3211
 
3212
  Imx_Set_Type( ds, Function);
3213
 
3214
  //remove protocol error from the device
3215
  if (!SaveError && dev) dev->SetProtocolError( 0);
3216
 
3217
  //check all devices for errors
3218
  for( int i = 0; i < DeviceCount(); i++)
3219
    error = GetDevice( i)->GetProtocolerror() ? error+1: error;
3220
 
3221
  LockRTDB( false);
3222
 
3223
  //set running state of the task
3224
  if (!error) MyRunTimeManager( -1, FLS_ACTIVE, NULL);
3225
 
3226
  //fill imx structure with correct task id
3227
  memcpy( &imxsys, &m_sImxSystem, sizeof( IMXSYSTEM));
3228
  imxsys.task_id = GetId();
3229
 
3230
  //check for the allowed maximum number of messages in the mailbox tag
3231
  unsigned int iMbxCount = 0;
3232
  //errors in retrieving the number of messages are ignored, vlaue will
3233
  //be zero, but if there is an error, there will be more errors and this
3234
  //error will never happen on its own.....
3235
  Imx_Q_Num_Mbx( &imxsys, Imx_Get_Snd_Mbx( ds), &iMbxCount); 
3236
 
3237
  //printf( "\nImxSend: Current = %d, Max = %d", iMbxCount, m_iIoxMaxMbxMsg);
3238
 
9 Marcel 3239
  if (iMbxCount <= (unsigned int)m_iIoxMaxMbxMsg)
1 mjordaan 3240
  {
3241
    //send imx message to translator
3242
    if ((error = Imx_Send( &imxsys, ds)) != GOOD)
3243
      MyRunTimeManager( error, FLS_ERROR, _T("IMX_SEND"), error, Imx_Get_Name( ds));
3244
  }
3245
  else
3246
    MyRunTimeManager( error, FLS_ERROR, _T("IMX_SEND"), (int)ERR_IOX_MAX_MESSAGE, Imx_Get_Name( ds));
3247
 
3248
  ReleaseRTDB();
3249
} //ImxSend
3250
 
3251
 
3252
/////////////////////////////////////////////////////////////////////////////
3253
// Descripton: Send an error response to the translator, use our own defined
3254
// task id(s), overrule th eone defined with imx.
3255
// 
3256
// Parameters: *ds - Pointer to an IMXDS structure, which is the currently 
3257
// processed dataset.
3258
// func - Functionality on the dataset which reported an error
3259
// code - error code for the failed functionality.
3260
// 
3261
// Returns: 
3262
// 
3263
// Comment: 
3264
// 
3265
/////////////////////////////////////////////////////////////////////////////
3266
void MyFlTask::ImxSendError( IMXDS *ds, int func, int code, CDeviceObject *dev)
3267
{
3268
 
3269
  IMXSYSTEM imxsys;
3270
  int error = 0;
3271
 
3272
 
3273
  //remove limit errors
3274
  CDatasetObject *dsobject = ds ? (CDatasetObject *)Imx_Get_Udata_Ptr( ds): NULL;
3275
  if (dsobject) dsobject->GetErrorOnLimit();
3276
 
3277
  //save the error on the device
3278
  if (dev) dev->SetProtocolError( code);
3279
 
3280
  LockRTDB( false);
3281
 
3282
  if (dev) dev->UpdateStatus( code);
3283
 
3284
  //fill imx structure with correct task id
3285
  memcpy( &imxsys, &m_sImxSystem, sizeof( IMXSYSTEM));
3286
  imxsys.task_id = GetId();
3287
 
3288
  //message for run time manager
3289
  switch (func)
3290
  {
3291
 
3292
    case 0: //read
3293
      MyRunTimeManager( code, FLS_ERROR, _T("IMX_READ_ERROR"), code, Imx_Get_Name( ds));
3294
      break;
3295
 
3296
    case 1: //write
3297
      MyRunTimeManager( code, FLS_ERROR, _T("IMX_WRITE_ERROR"), code, Imx_Get_Name( ds));
3298
      break;
3299
 
3300
    case 2: //receive
3301
      MyRunTimeManager( code, FLS_ERROR, _T("IMX_RECV_ERROR"), code, Imx_Get_Name( ds));
3302
      break;
3303
  }
3304
 
3305
  //check for the allowed maximum number of messages in the mailbox tag
3306
  unsigned int iMbxCount = 0;
3307
  //errors in retrieving the number of messages are ignored, vlaue will
3308
  //be zero, but if there is an error, there will be more errors and this
3309
  //error will never happen on its own.....
3310
  Imx_Q_Num_Mbx( &imxsys, Imx_Get_Snd_Mbx( ds), &iMbxCount); 
3311
 
3312
  //printf( "\nImxSendError: Current = %d, Max = %d", iMbxCount, m_iIoxMaxMbxMsg);
3313
 
9 Marcel 3314
  if (iMbxCount <= (unsigned int)m_iIoxMaxMbxMsg)
1 mjordaan 3315
  {
3316
 
3317
    if ((error = Imx_Send_Error( &imxsys, ds, code)) != GOOD)
3318
      MyRunTimeManager( error, FLS_ERROR, _T("IMX_SEND_ERROR"), error, Imx_Get_Name( ds));
3319
  }
3320
  else
3321
    MyRunTimeManager( error, FLS_ERROR, _T("IMX_SEND"), (int)ERR_IOX_MAX_MESSAGE, Imx_Get_Name( ds));
3322
 
3323
  ReleaseRTDB();
3324
 
3325
  return;
3326
} //ImxSendError
3327
 
3328
 
3329
/////////////////////////////////////////////////////////////////////////////
3330
// Descripton: Build header strucuture for message with device settings for the
3331
// specified message type
3332
// 
3333
// Parameters: buffer - Pointer to buffer to fill with header, the header length 
3334
//                      is 15 bytes, user needs to supply a buffer which is large
3335
//                      enough.
3336
//             device - Pointer to device object, settings for the header are 
3337
//                      stored on the device object.
3338
//             datalen - This is an integer telling how many databytes will be 
3339
//                       included in the message.
3340
// 
3341
// Returns: 
3342
// 
3343
// Comment: 
3344
// 
3345
/////////////////////////////////////////////////////////////////////////////
3346
void MyFlTask::ImBasBuildHeader( char *buffer, CDeviceObject *device, 
3347
                                 int *datalen, int type)
3348
{
3349
 
3350
  //device object is reauired
3351
  if (!device) return;
3352
 
3353
  //fill bytes 0 and 1 with source id
3354
  buffer[ 0] = m_sSource[ 0];
3355
  buffer[ 1] = m_sSource[ 1];
3356
 
3357
  //fill bytes 2 and 3 with destination id
3358
  buffer[ 2] = m_sDestination[ 0];
3359
  buffer[ 3] = m_sDestination[ 1];
3360
 
3361
  //fill bytes 4 and 5 with message number
3362
  switch (type)
3363
  {
3364
 
3365
    case DS_COMMAND_BOOL:      
3366
    case DS_COMMAND_INT:      
3367
    case DS_COMMAND_LONG:      
3368
    case DS_COMMAND_REAL:      
3369
    case DS_COMMAND_CHAR:     
3370
      device->IncSequenceNr();
3371
      buffer[ 4] = m_sIdCommand[ 0]; 
3372
      buffer[ 5] = m_sIdCommand[ 1]; break;
3373
 
3374
    case DSW_COMMAND_BOOL:      
3375
    case DSW_COMMAND_INT:      
3376
    case DSW_COMMAND_LONG:      
3377
    case DSW_COMMAND_REAL:      
3378
    case DSW_COMMAND_CHAR:    
3379
      device->IncSequenceNr();
3380
      buffer[ 4] = m_sIdCommand[ 0]; 
3381
      buffer[ 5] = m_sIdCommand[ 1]; break;
3382
 
3383
    case DS_PARAMETER_BOOL:
3384
    case DS_PARAMETER_INT: 
3385
    case DS_PARAMETER_LONG:
3386
    case DS_PARAMETER_REAL:
3387
    case DS_PARAMETER_CHAR:   
3388
      device->IncSequenceNr();
3389
      buffer[ 4] = m_sIdParameter[ 0]; 
3390
      buffer[ 5] = m_sIdParameter[ 1]; break;
3391
 
3392
    case DSW_PARAMETER_BOOL:
3393
    case DSW_PARAMETER_INT: 
3394
    case DSW_PARAMETER_LONG:
3395
    case DSW_PARAMETER_REAL:
3396
    case DSW_PARAMETER_CHAR: 
3397
      device->IncSequenceNr();
3398
      buffer[ 4] = m_sIdSetParameter[ 0]; 
3399
      buffer[ 5] = m_sIdSetParameter[ 1]; break;
3400
 
3401
    case DS_STATUS_BOOL:
3402
    case DS_STATUS_INT:
3403
    case DS_STATUS_LONG:
3404
    case DS_STATUS_REAL:
3405
    case DS_STATUS_CHAR:     
3406
      device->IncSequenceNr();
3407
      buffer[ 4] = m_sIdStatus[ 0]; 
3408
      buffer[ 5] = m_sIdStatus[ 1]; break;
3409
 
3410
    case DSW_STATUS_BOOL:
3411
    case DSW_STATUS_INT:
3412
    case DSW_STATUS_LONG:
3413
    case DSW_STATUS_REAL:
3414
    case DSW_STATUS_CHAR:    
3415
      device->IncSequenceNr();
3416
      buffer[ 4] = m_sIdStatus[ 0]; 
3417
      buffer[ 5] = m_sIdStatus[ 1]; break;
3418
 
3419
    case DS_STATINFO_BOOL:
3420
    case DS_STATINFO_INT:
3421
    case DS_STATINFO_LONG:
3422
    case DS_STATINFO_REAL:
3423
    case DS_STATINFO_CHAR:   
3424
      device->IncSequenceNr();
3425
      buffer[ 4] = m_sIdStatistical[ 0]; 
3426
      buffer[ 5] = m_sIdStatistical[ 1]; break;
3427
 
3428
    case DSW_STATINFO_BOOL:
3429
    case DSW_STATINFO_INT:
3430
    case DSW_STATINFO_LONG:
3431
    case DSW_STATINFO_REAL:
3432
    case DSW_STATINFO_CHAR:  
3433
      device->IncSequenceNr();
3434
      buffer[ 4] = m_sIdStatistical[ 0]; 
3435
      buffer[ 5] = m_sIdStatistical[ 1]; break;
3436
 
3437
    case DS_STATDEL_BOOL:
3438
    case DS_STATDEL_INT:
3439
    case DS_STATDEL_LONG:
3440
    case DS_STATDEL_REAL:
3441
    case DS_STATDEL_CHAR:    
3442
      device->IncSequenceNr();
3443
      buffer[ 4] = m_sIdStatistical[ 0]; 
3444
      buffer[ 5] = m_sIdStatistical[ 1]; break;
3445
 
3446
    case DSW_STATDEL_BOOL:
3447
    case DSW_STATDEL_INT:
3448
    case DSW_STATDEL_LONG:
3449
    case DSW_STATDEL_REAL:
3450
    case DSW_STATDEL_CHAR:   
3451
      device->IncSequenceNr();
3452
      buffer[ 4] = m_sIdStatistical[ 0]; 
3453
      buffer[ 5] = m_sIdStatistical[ 1]; break;
3454
 
3455
    case DS_EXCEPTION:
3456
    case DSW_EXCEPTION:      
3457
      buffer[ 4] = m_sIdException[ 0]; 
3458
      buffer[ 5] = m_sIdException[ 1]; break;
3459
 
3460
    default:       
3461
    case DSW_LIFESIGN:
3462
    case DS_LIFESIGN:        
3463
      buffer[ 4] = m_sIdLifeSign[ 0]; 
3464
      buffer[ 5] = m_sIdLifeSign[ 1]; break;
3465
  }
3466
 
3467
  //fill bytes 6 and 7 with version
3468
  buffer[ 6] = m_sProtocolVersion[ 0];
3469
  buffer[ 7] = m_sProtocolVersion[ 1];
3470
 
3471
  //fill bytes 8 and 9 with sequence number
3472
  if ((type == DS_LIFESIGN) ||(type == DSW_LIFESIGN))
3473
    buffer[ 8] = buffer[ 9] = '0';
3474
  else
3475
    if (type == DSW_EXCEPTION) 
3476
      sprintf( &buffer[8], _T("%02d"), device->GetReplySequence());
3477
    else 
3478
      sprintf( &buffer[8], _T("%02d"), device->GetSequenceNr());
3479
 
3480
  //fill bytes 10, 11 and 12 with data length
3481
  if (*datalen > 999) *datalen = 999;
3482
  sprintf( &buffer[ 10], _T("%03d"), *datalen);
3483
 
3484
  //fill bytes 13 and 14 with subsystem id
3485
  buffer[ 13] = device->GetSubId()[ 0];
3486
  buffer[ 14] = device->GetSubId()[ 1];
3487
 
3488
  //add terminator
3489
  buffer[ PROT_HEADER_LEN + *datalen] = ImBasGetTerminator();
3490
} //ImBasBuildHeader
3491
 
3492
 
3493
/////////////////////////////////////////////////////////////////////////////
3494
// Descripton: Convert Imx data to dat strucutres used in the IM-BAS protocol.
3495
// If the conversion fails, e.g the requested message type is not implemented
3496
// in the protocol, a value of -1 is returned. Otherwise the length in bytes 
3497
// of the data buffer is returned.
3498
// 
3499
// Parameters: buffer - pointer to a data buffer i which the message is stored.
3500
// type - The type of the message to convert
3501
// start - Start address of the data
3502
// length - umber of addresses to read/write.
3503
// 
3504
// Returns: The number of bytes which are in the buffer ready for sending on
3505
// the network. If this value is -1, an error has occured, and one should not
3506
// send the message.
3507
// 
3508
// Comment: 
3509
// Imx_Get_Word( IMXDS *ds, i16 *data) {
3510
/////////////////////////////////////////////////////////////////////////////
3511
int MyFlTask::ImBasImx2Data( char *buf, int type, int start, 
3512
                             int *length, CDeviceObject *device) //IMXDS *ds)
3513
{
3514
 
3515
  int retlen = 0;
3516
  int i, k;
3517
  int dslen;
3518
  char *buffer = NULL;//[ IMX_BUFFER_SIZE];
3519
  char del = '0';
3520
  int startds = 0;
3521
  IMXDS *ds = (device) ? device->GetCurrentImxDataset(): NULL;
3522
  CDatasetObject *dataset = NULL;
3523
  char tmpbuf[20];
3524
 
3525
 
3526
  //get registered dataset
3527
  if (ds) dataset = (CDatasetObject *)Imx_Get_Udata_Ptr( ds);
3528
 
3529
  //update buf pointer for header
3530
  buf += PROT_HEADER_LEN;
3531
 
3532
  //check length of dataset
3533
  if (*length > 99) *length = 99;
3534
 
3535
  if (ds)
3536
    buffer = Imx_Get_U_Buffer( ds);
3537
 
3538
  //fill buffer with data, filling depends on type of dataset
3539
  switch (type)
3540
  {
3541
 
3542
    case DSW_COMMAND_BOOL:
3543
    case DSW_PARAMETER_BOOL:
3544
 
3545
      if (!ds) return 0;
3546
      startds = Imx_Get_Start( ds);
3547
 
3548
      buf[ 0] = 'B'; //field type
3549
      sprintf( &buf[ 1], "%02d", *length);
3550
      dslen = *length;
3551
 
3552
      for (i = 0, k = 0; i < *length; i++)
3553
      {
3554
 
3555
        if ((dataset == NULL) ||   
3556
            ((dataset != NULL) && (dataset->FindAddressIndex(start + i) != 0)))
3557
        {
3558
          //set field index
3559
          sprintf( &buf[ 3 + k*6], "%04d", start + i);
3560
 
3561
          //assume boundary is byte
3562
          buf[ 7 + k*6] = (buffer[ i]) ? '1': '0';
3563
          buf[ 8 + k++*6] = ImBasGetDelimiter(); //';';
3564
        }
3565
        else //skip address, adjust length with one element
3566
        {
3567
 
3568
          sprintf( &tmpbuf[ 1], "%02d", --dslen);
3569
          buf[ 1] = tmpbuf[ 1];
3570
          buf[ 2] = tmpbuf[ 2];
3571
        }
3572
      }
3573
 
3574
      retlen = (dslen * 6) + 3; //length of data
3575
      break;
3576
 
3577
    case DSW_COMMAND_INT:
3578
    case DSW_PARAMETER_INT:
3579
 
3580
      if (!ds) return 0;
3581
      startds = Imx_Get_Start( ds) / 2;
3582
 
3583
      //fill request buffer
3584
      buf[ 0] = 'I';
3585
 
3586
      sprintf( &buf[ 1], "%02d", *length);
3587
      dslen = *length;
3588
 
3589
      for (i = 0, k = 0; i < *length; i++)
3590
      {
3591
 
3592
        if ((dataset == NULL) ||   
3593
            ((dataset != NULL) && (dataset->FindAddressIndex(start + i) != 0)))
3594
        {
3595
 
3596
          sprintf( &buf[ 3 + k*8], "%04d", start + i);
3597
 
3598
          //assume boundary is word
3599
          int x = Imx_Get_Word( ds, (u16 *)&buffer[ 2*i]);
3600
 
3601
          //check value
3602
          if (device && ((x < 0) || (x > 999))) dataset->SetErrorOnLimit();
3603
          if (x > 999) x = 999;
3604
          if (x < 0) x = 0;
3605
 
3606
          sprintf( &buf[ 7 + k*8], "%03d", x);
3607
          buf[ 10 + k++*8] = ImBasGetDelimiter(); //';';
3608
        }
3609
        else //skip address, adjust length with one element
3610
        {
3611
 
3612
          sprintf( &tmpbuf[ 1], "%02d", --dslen);
3613
          buf[ 1] = tmpbuf[ 1];
3614
          buf[ 2] = tmpbuf[ 2];
3615
        }
3616
      }
3617
 
3618
      retlen = (dslen * 8) + 3;
3619
      break;
3620
 
3621
    case DSW_COMMAND_LONG:
3622
    case DSW_PARAMETER_LONG:
3623
 
3624
      if (!ds) return 0;
3625
      startds = Imx_Get_Start( ds) / 4;
3626
 
3627
      //fill request buffer
3628
      buf[ 0] = 'L';
3629
 
3630
      sprintf( &buf[ 1], "%02d", *length);
3631
      dslen = *length;
3632
 
3633
      for (i = 0, k = 0; i < *length; i++)
3634
      {
3635
 
3636
        if ((dataset == NULL) ||   
3637
            ((dataset != NULL) && (dataset->FindAddressIndex(start + i) != 0)))
3638
        {
3639
 
3640
          sprintf( &buf[ 3 + k*11], "%04d", start + i);
3641
 
3642
          //assume boundary is long
3643
          long x = Imx_Get_Long( ds, (u32 *)&buffer[ 4*i]);
3644
 
3645
          //check value
3646
          if (device && ((x < 0) || (x > 999999))) dataset->SetErrorOnLimit();
3647
          if (x > 999999) x = 999999;
3648
          if (x < 0) x = 0;
3649
 
3650
          sprintf( &buf[ 7 + k*11], "%06d", x);
3651
          buf[ 13 + k++*11] = ImBasGetDelimiter(); //';';
3652
        }
3653
        else //skip address, adjust length with one element
3654
        {
3655
 
3656
          sprintf( &tmpbuf[ 1], "%02d", --dslen);
3657
          buf[ 1] = tmpbuf[ 1];
3658
          buf[ 2] = tmpbuf[ 2];
3659
        }
3660
      }
3661
 
3662
      retlen = (dslen * 11) + 3;
3663
      break;
3664
 
3665
    case DSW_COMMAND_REAL:
3666
    case DSW_PARAMETER_REAL:
3667
 
3668
      if (!ds) return 0;
3669
      startds = Imx_Get_Start( ds) / IMX_DBL_BND;
3670
 
3671
      retlen = (*length * 22) + 3;
3672
 
3673
      //fill request buffer
3674
      buf[ 0] = 'R';
3675
 
3676
      sprintf( &buf[ 1], "%02d", *length);
3677
      dslen = *length;
3678
 
3679
      for (i = 0, k = 0; i < *length; i++)
3680
      {
3681
 
3682
        if ((dataset == NULL) ||   
3683
            ((dataset != NULL) && (dataset->FindAddressIndex(start + i) != 0)))
3684
        {
3685
 
3686
          sprintf( &buf[ 3 + k*22], "%04d", start + i);
3687
 
3688
          //assume boundary is double, elements are double's
3689
          double x = Imx_Get_Double( ds, (double *)&buffer[ IMX_DBL_BND*i]);
3690
 
3691
          //check value
3692
          if (device && ((x < 0) || (x > 99999999.99999999))) dataset->SetErrorOnLimit();
3693
          if (x > 99999999.99999999) x = 99999999.99999999;
3694
          if (x < 0) x = 0;
3695
 
3696
          sprintf( &buf[ 7 + k*22], "%017.8f", (double)x);
3697
          buf[ 24 + k++*22] = ImBasGetDelimiter(); //';';
3698
        }
3699
        else //skip address, adjust length with one element
3700
        {
3701
 
3702
          sprintf( &tmpbuf[ 1], "%02d", --dslen);
3703
          buf[ 1] = tmpbuf[ 1];
3704
          buf[ 2] = tmpbuf[ 2];
3705
        }
3706
      }
3707
      break;
3708
 
3709
    case DSW_COMMAND_CHAR:
3710
    case DSW_PARAMETER_CHAR:
3711
 
3712
      if (!ds) return 0;
3713
      startds = Imx_Get_Start( ds) / (PROT_STRING_SIZE/IMX_LONG_BND);
3714
 
3715
      //fill request buffer
3716
      buf[ 0] = 'S';
3717
 
3718
      sprintf( &buf[ 1], "%02d", *length);
3719
      dslen = *length;
3720
 
3721
      //every string is supposed to be 20 characters long
3722
      for (i = 0, k = 0; i < *length; i++)
3723
      {
3724
 
3725
        if ((dataset == NULL) ||   
3726
            ((dataset != NULL) && (dataset->FindAddressIndex(start + i) != 0)))
3727
        {
3728
 
3729
          sprintf( &buf[ 3 + i*25], "%04d", start + i);
3730
 
3731
          //assume boundary is byte
3732
          for (int x = 0; x < PROT_STRING_SIZE; x++)
3733
          {
3734
            if (buffer[ (i+start-startds)*PROT_STRING_SIZE + x] == 0)
3735
              buf[ 7 + i*25 + x] = ' '; //trailing spaces
3736
            else
3737
              buf[ 7 + i*25 + x] = buffer[ (i+start-startds)*PROT_STRING_SIZE + x];
3738
          }
3739
 
3740
          buf[ 7 + i*25 + PROT_STRING_SIZE] = ImBasGetDelimiter(); //';';
3741
        }
3742
        else //skip address, adjust length with one element
3743
        {
3744
 
3745
          sprintf( &tmpbuf[ 1], "%02d", --dslen);
3746
          buf[ 1] = tmpbuf[ 1];
3747
          buf[ 2] = tmpbuf[ 2];
3748
        }
3749
      }
3750
 
3751
      retlen = (dslen * 25) + 3;
3752
      break;
3753
 
3754
    case DS_PARAMETER_BOOL:
3755
    case DS_PARAMETER_INT:
3756
    case DS_PARAMETER_LONG:
3757
    case DS_PARAMETER_REAL:
3758
    case DS_PARAMETER_CHAR:
3759
 
3760
      //fill request buffer
3761
      if (type == DS_PARAMETER_BOOL) buf[ 0] = 'B';
3762
      if (type == DS_PARAMETER_INT)  buf[ 0] = 'I';
3763
      if (type == DS_PARAMETER_LONG) buf[ 0] = 'L';
3764
      if (type == DS_PARAMETER_REAL) buf[ 0] = 'R';
3765
      if (type == DS_PARAMETER_CHAR) buf[ 0] = 'S';
3766
 
3767
      sprintf( &buf[ 1], "%02d", *length);
3768
      dslen = *length;
3769
 
3770
      for (i = 0, k = 0; i < *length; i++)
3771
      {
3772
 
3773
        if ((dataset == NULL) ||   
3774
            ((dataset != NULL) && (dataset->FindAddressIndex(start + i) != 0)))
3775
        {
3776
 
3777
          sprintf( &buf[ 3 + k*5], "%04d", start + i);
3778
 
3779
          //assume boundary is byte
3780
          buf[ 7 + k++*5] = ImBasGetDelimiter(); //';';
3781
        }
3782
        else //skip address, adjust length with one element
3783
        {
3784
 
3785
          sprintf( &tmpbuf[ 1], "%02d", --dslen);
3786
          buf[ 1] = tmpbuf[ 1];
3787
          buf[ 2] = tmpbuf[ 2];
3788
        }
3789
      }
3790
 
3791
      retlen = (dslen * 5) + 3;
3792
      break;
3793
 
3794
    case DS_STATUS_BOOL:
3795
    case DS_STATUS_INT:
3796
    case DS_STATUS_LONG:
3797
    case DS_STATUS_REAL:
3798
    case DS_STATUS_CHAR:
3799
      retlen = 0;
3800
      break;
3801
 
3802
    case DS_STATDEL_BOOL:
3803
    case DS_STATDEL_INT:
3804
    case DS_STATDEL_LONG:
3805
    case DS_STATDEL_REAL:
3806
    case DS_STATDEL_CHAR: del = '1';
3807
    case DS_STATINFO_BOOL:
3808
    case DS_STATINFO_INT:
3809
    case DS_STATINFO_LONG:
3810
    case DS_STATINFO_REAL:
3811
    case DS_STATINFO_CHAR:
3812
 
3813
      //fill request buffer
3814
      if ((type == DS_STATDEL_BOOL) || (type == DS_STATINFO_BOOL)) buf[ 0] = 'B';
3815
      if ((type == DS_STATDEL_INT)  || (type == DS_STATINFO_INT))  buf[ 0] = 'I';
3816
      if ((type == DS_STATDEL_LONG) || (type == DS_STATINFO_LONG)) buf[ 0] = 'L';
3817
      if ((type == DS_STATDEL_REAL) || (type == DS_STATINFO_REAL)) buf[ 0] = 'R';
3818
      if ((type == DS_STATDEL_CHAR) || (type == DS_STATINFO_CHAR)) buf[ 0] = 'S';
3819
 
3820
      sprintf( &buf[ 1], "%02d", *length);
3821
      dslen = *length;
3822
 
3823
      for (i = 0, k = 0; i < *length; i++)
3824
      {
3825
 
3826
        if ((dataset == NULL) ||   
3827
            ((dataset != NULL) && (dataset->FindAddressIndex(start + i) != 0)))
3828
        {
3829
 
3830
          sprintf( &buf[ 3 + k*5], "%04d", start + i);
3831
 
3832
          //assume boundary is byte
3833
          buf[ 7 + k++*5] = ImBasGetDelimiter(); //';';
3834
        }
3835
        else //skip address, adjust length with one element
3836
        {
3837
 
3838
          sprintf( &tmpbuf[ 1], "%02d", --dslen);
3839
          buf[ 1] = tmpbuf[ 1];
3840
          buf[ 2] = tmpbuf[ 2];
3841
        }
3842
      }
3843
 
3844
      retlen = (dslen * 5) + 4;
3845
 
3846
      //erase indicator
3847
      buf[ retlen-1] = del;
3848
      break;
3849
 
3850
    case DSW_LIFESIGN:
3851
    case DSW_EXCEPTION:
3852
      retlen = 0;
3853
      break;
3854
 
3855
    default:       
3856
      retlen = -1;
3857
      break;
3858
  }
3859
 
3860
  //copy internal buffer to user buffer, doing so 
3861
  //allows the user to specify 1 buffer for input/output
3862
  //if (retlen > 0) memcpy( &buffer[ PROT_HEADER_LEN], buf, retlen);
3863
 
3864
  return retlen; //return data length
3865
} //ImBasImx2Data
3866
 
3867
 
3868
/////////////////////////////////////////////////////////////////////////////
3869
// Descripton: Im-bas protocl data  converson to imx data. The raw data in 'source'
3870
// is converted to IMX format and stored in 'dest'. These buffers may overlap or be 
3871
// the same memory location.
3872
// 
3873
// Parameter: 
3874
// *dest - pointer to destination databuffer, this is the converted 
3875
//         data in imx-format.
3876
// *source - pointer to source databauffer, this is the raw data in 
3877
//           IM-BAS format.
3878
// *ds - pointer to an imx dataset structure.
3879
// *datalen -
3880
// start - Start address of the data, determined before calling this function.
3881
//         This address can be the same as the start address of the dataset, but will
3882
//         not be if the complete dataset is received in more then one TM-buffer.
3883
// *length - Output parameter of the function, the actual length of the received 
3884
//           data is stored.
3885
//
3886
// Returns: Error code, or success as a zero value.
3887
// 
3888
// Comment: 
3889
// 
3890
/////////////////////////////////////////////////////////////////////////////
3891
int MyFlTask::ImBasData2Imx( char *dest, char *source, IMXDS *ds, int start,
3892
                             int *length)
3893
{
3894
 
3895
  int dlen = ImBasGetDataLength( source, PROT_HEADER_LEN); //get the data length
3896
  int dtype = 0;
3897
  int dsize = 0;
3898
  //use temp buffer, this allows source and destination to overlap
3899
  char buf[ IMX_BUFFER_SIZE]; 
3900
  char tmp[ 100];
3901
  short itmp = Imx_Get_Boundary( ds);
3902
  int dslength = Imx_Get_Len( ds);
3903
  long ltmp;
3904
  double dtmp;
3905
  CString str;
3906
  int mystart = 0x7fffffff;
3907
  int mymax = 0;
3908
  int DataType = (CDatasetObject *)Imx_Get_Udata_Ptr( ds) ? ((CDatasetObject *)Imx_Get_Udata_Ptr( ds))->GetType() % 10 : -1;
3909
 
3910
 
3911
  //get the data type
3912
  switch (source[ PROT_HEADER_LEN])
3913
  {
3914
 
3915
    case 'B': dtype = IMX_BYTE_BND; dsize = 1; break;
3916
    case 'I': dtype = IMX_WORD_BND; dsize = 3; break;
3917
    case 'L': dtype = IMX_LONG_BND; dsize = 6; break;
3918
    case 'R': dtype = IMX_DBL_BND; dsize = 17; break;
3919
    case 'S': dtype = PROT_STRING_SIZE; dsize = PROT_STRING_SIZE; 
3920
 
3921
              //make sure the boundary is long
3922
              if (Imx_Get_Boundary( ds) != IMX_LONG_BND)
3923
                Imx_Set_Boundary( ds, IMX_LONG_BND);
3924
              break;
3925
  }
3926
 
3927
  //check if data types match
3928
  switch (DataType)
3929
  {
3930
 
3931
    case 0: //boolean data
3932
      if (source[ PROT_HEADER_LEN] != 'B') return ERR_DATATYPE_INV;
3933
      break;
3934
 
3935
    case 1: //integer data
3936
      if (source[ PROT_HEADER_LEN] != 'I') return ERR_DATATYPE_INV;
3937
      break;
3938
 
3939
    case 2: //long data
3940
      if (source[ PROT_HEADER_LEN] != 'L') return ERR_DATATYPE_INV;
3941
      break;
3942
 
3943
    case 3: //real data
3944
      if (source[ PROT_HEADER_LEN] != 'R') return ERR_DATATYPE_INV;
3945
      break;
3946
 
3947
    case 4: //string data
3948
      if (source[ PROT_HEADER_LEN] != 'S') return ERR_DATATYPE_INV;
3949
      break;
3950
 
3951
    default: return ERR_UNKNOWN_DATATYPE;
3952
  }
3953
 
3954
  //calculate the number of elements, return if there is no data received
3955
  if ((dlen = (dlen - 3) / (dsize + 5)) <= 0) return *length = 0;
3956
 
3957
  //start with a minimum length of 1 element
3958
  if (*length <= 0) *length = 1 * (dtype / Imx_Get_Boundary( ds));
3959
 
3960
  //initialise the internal buffer to default values
3961
  ImBasInitImxData( buf, IMX_BUFFER_SIZE, source[ PROT_HEADER_LEN]);
3962
 
3963
  //find the length of the dataset and convert the data
3964
  for (int i = 0; i < dlen; i++)
3965
  {
3966
 
3967
    strncpy( tmp, &source[ PROT_HEADER_LEN + 3 + (i * (5 + dsize))], PROT_INDEX_SIZE); 
3968
    tmp[ PROT_INDEX_SIZE] = '\0';
3969
 
3970
    int idx = atoi( tmp); //address
3971
    ltmp = idx * (dtype / (int)Imx_Get_Boundary( ds));
3972
 
3973
    //if the address lower then requested, skip and continue
3974
    if (start > ((idx * dtype) / Imx_Get_Boundary( ds))) continue;
3975
 
3976
    if (((idx * dtype) / Imx_Get_Boundary( ds)) - start >= dslength)
3977
      continue;
3978
 
3979
    //calculated start address must be above start of dataset
3980
    ltmp = ltmp < start ? start : ltmp; 
3981
    mystart = ltmp < mystart ? ltmp : mystart;
3982
 
3983
    //max address in received data
3984
    mymax = ltmp > mymax ? ltmp : mymax;
3985
 
3986
    *length = (ltmp - start + (dtype / Imx_Get_Boundary( ds))) > *length ? 
3987
      ltmp - start + (dtype / Imx_Get_Boundary( ds)) : *length;
3988
 
3989
 
3990
    switch (source[ PROT_HEADER_LEN])
3991
    {
3992
 
3993
      case 'B':
3994
        buf[ (idx - start) * dtype] = source[ PROT_HEADER_LEN + 7 + (i * (5 + dsize))] - '0';
3995
        break;
3996
 
3997
      case 'I':
3998
        strncpy( tmp, &source[ PROT_HEADER_LEN + 7 + (i * (5 + dsize))], dsize);
3999
        tmp[ dsize] = '\0';
4000
        itmp = atoi( tmp);
4001
        Imx_Set_Word( ds, (u16 *)&buf[ (idx - start) * Imx_Get_Boundary( ds)], (u16 *)&itmp);
4002
        break;
4003
 
4004
      case 'L':
4005
        strncpy( tmp, &source[ PROT_HEADER_LEN + 7 + (i * (5 + dsize))], dsize);
4006
        tmp[ dsize] = '\0';
4007
        ltmp = atol( tmp);
4008
        Imx_Set_Long( ds, (u32 *)&buf[ (idx - start) * dtype], (u32 *)&ltmp);
4009
        break;
4010
 
4011
      case 'R':
4012
        strncpy( tmp, &source[ PROT_HEADER_LEN + 7 + (i * (5 + dsize))], dsize);
4013
        tmp[ dsize] = '\0';
4014
        dtmp = atof( tmp);
4015
 
4016
        if (DebugForReals())
4017
          CodeTrace( "REAL_INFO", 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, tmp, dtmp);
4018
 
4019
        Imx_Set_Double( ds, (double *)&buf[ (idx - start) * dtype], (double *)&dtmp);
4020
        break;
4021
 
4022
      case 'S':
4023
        strncpy( tmp, &source[ PROT_HEADER_LEN + 7 + (i * (5 + dsize))], dsize);
4024
        tmp[ dsize] = '\0'; //copy string to tmp
4025
 
4026
        //do the trimming of spaces
4027
        str = tmp;
4028
        if (GetSpaceTrimLeft())str.TrimLeft();
4029
        if (GetSpaceTrimRight()) str.TrimRight();
4030
 
4031
        int xstart = start * Imx_Get_Boundary( ds);
4032
 
4033
        //copy the string to the imx buffer
4034
        int ix = (idx * (dtype)) - xstart + str.GetLength();
4035
        memset( &buf[ (idx * dtype) - xstart + str.GetLength()], 0, dsize - str.GetLength());
4036
        strncpy( &buf[ (idx * dtype) - xstart], str, str.GetLength()); 
4037
        break;
4038
    }
4039
  }
4040
 
4041
  //copy the buffer
4042
  if (dlen > 0)
4043
  {
4044
 
4045
    //received no data fro dataset
4046
    if ((mystart == 0x7fffffff) || (mystart < start)) 
4047
      return ERR_INVALID_ADR;
4048
 
4049
    //quit if data does not fit in the buffer
4050
    if (mystart - start < 0) 
4051
      return ERR_INVALID_ADR;
4052
 
4053
    //if (PROT_HEADER_LEN + mystart - start + (dtype * dlen) > IMX_BUFFER_SIZE) return ERR_INVALID_ADR;
4054
    if ((mymax - start + dtype / Imx_Get_Boundary( ds)) * Imx_Get_Boundary( ds) > IMX_BUFFER_SIZE)
4055
      return ERR_INVALID_ADR;
4056
 
4057
    //preserve the space for the IM-BAS header
4058
    memcpy( &dest[ PROT_HEADER_LEN + (mystart - start)*Imx_Get_Boundary( ds)], 
4059
            &buf[ (mystart - start) * Imx_Get_Boundary( ds)], 
4060
            (mymax - start + dtype / Imx_Get_Boundary( ds)) * Imx_Get_Boundary( ds));
4061
            //dtype * dlen);
4062
  }
4063
 
4064
  return 0;
4065
} //ImBasData2Imx
4066
 
4067
 
4068
/////////////////////////////////////////////////////////////////////////////
4069
// Descripton: Calculate the maximum length of a message, for which the response
4070
// size will less then 999 data bytes. 
4071
// 
4072
// Parameters: 
4073
// 
4074
// Returns: 
4075
// 
4076
// Comment: 
4077
// 
4078
/////////////////////////////////////////////////////////////////////////////
4079
int MyFlTask::ImBasMaxLength( int type)
4080
{
4081
 
4082
 
4083
  //calculate the maximum length for response size <= 999 data bytes
4084
  switch (type)
4085
  {
4086
 
4087
    case DS_COMMAND_BOOL:
4088
    case DS_COMMAND_INT:
4089
    case DS_PARAMETER_BOOL:
4090
    case DS_PARAMETER_INT:
4091
    case DS_STATUS_BOOL:
4092
    case DS_STATUS_INT:
4093
    case DS_STATINFO_BOOL:
4094
    case DS_STATINFO_INT:
4095
    case DS_STATDEL_BOOL:
4096
    case DS_STATDEL_INT:
4097
    case DS_EXCEPTION:
4098
    case DS_LIFESIGN: return 99;
4099
 
4100
    case DS_COMMAND_LONG:
4101
    case DS_PARAMETER_LONG:
4102
    case DS_STATUS_LONG:
4103
    case DS_STATINFO_LONG:
4104
    case DS_STATDEL_LONG: return 90;
4105
 
4106
    case DS_COMMAND_REAL:
4107
    case DS_PARAMETER_REAL:
4108
    case DS_STATUS_REAL:
4109
    case DS_STATINFO_REAL:
4110
    case DS_STATDEL_REAL: return 45;
4111
 
4112
    case DS_COMMAND_CHAR:
4113
    case DS_PARAMETER_CHAR:
4114
    case DS_STATUS_CHAR:
4115
    case DS_STATINFO_CHAR:
4116
    case DS_STATDEL_CHAR: return 39;
4117
 
4118
    case DSW_COMMAND_BOOL:
4119
    case DSW_COMMAND_INT:
4120
    case DSW_PARAMETER_BOOL:
4121
    case DSW_PARAMETER_INT:
4122
    case DSW_STATUS_BOOL:
4123
    case DSW_STATUS_INT:
4124
    case DSW_STATINFO_BOOL:
4125
    case DSW_STATINFO_INT:
4126
    case DSW_STATDEL_BOOL:
4127
    case DSW_STATDEL_INT:
4128
    case DSW_EXCEPTION:
4129
    case DSW_LIFESIGN: return 99;
4130
 
4131
    case DSW_COMMAND_LONG:
4132
    case DSW_PARAMETER_LONG:
4133
    case DSW_STATUS_LONG:
4134
    case DSW_STATINFO_LONG:
4135
    case DSW_STATDEL_LONG: return 90;
4136
 
4137
    case DSW_COMMAND_REAL:
4138
    case DSW_PARAMETER_REAL:
4139
    case DSW_STATUS_REAL:
4140
    case DSW_STATINFO_REAL:
4141
    case DSW_STATDEL_REAL: return 45;
4142
 
4143
    case DSW_COMMAND_CHAR:
4144
    case DSW_PARAMETER_CHAR:
4145
    case DSW_STATUS_CHAR:
4146
    case DSW_STATINFO_CHAR:
4147
    case DSW_STATDEL_CHAR: return 39;
4148
  }
4149
 
4150
  return 0;
4151
}
4152
 
4153
 
4154
/////////////////////////////////////////////////////////////////////////////
4155
// Description: The function updates the connection state. This connection state 
4156
// is registered for every device, and used to update the a tag which is configured
4157
// for the device to represent the actual conneciton state.
4158
// If this tag is a message tag, three translations are used to convert the state
4159
// from an integer value to a string: DEVICE_NOT_CONNECTED --> CONN_LISTENING = 
4160
// 'Listening', DEVICE_CONNECTED --> CONN_LIFESIGN = 'Connected' and DEVICE_DISCONNECTING
4161
// --> CONN_DICONNECT = 'Disconnecting'.
4162
// 
4163
// Parameter: state - Connection state of the device, this can be: DEVICE_NOT_CONNECTED,
4164
// DEVICE_CONNECTED or DEVICE_DISCONNECTING.
4165
 
4166
// 
4167
// Returns: 
4168
// 
4169
// Comment: 
4170
// 
4171
/////////////////////////////////////////////////////////////////////////////
4172
void CDeviceObject::UpdateConnection( int state)
4173
{ 
4174
 
4175
  CString xl[5] = {_T("CONN_LISTENING"), _T("CONN_DISCONNECT"), _T("CONN_CONNECT"), 
4176
                   _T("CONN_TCPIP_ONLY"), _T("CONN_LIFESIGN")};
4177
 
4178
 
4179
  //update internal state
4180
  m_iConnected = state;
4181
  MyStatus.Connection = m_iConnected;
4182
 
4183
  //update connection info for device status
4184
  if (state == DEVICE_CONNECTED)
4185
  {
4186
 
4187
    //get the local IP-address and port number
4188
    struct sockaddr_in sa;
4189
    int len = sizeof( struct sockaddr_in);
4190
    int pret;
4191
 
4192
    pret = getsockname( GetSocket(), (struct sockaddr *)&sa, &len);
4193
    if (!pret)
4194
    {
4195
 
4196
      strcpy( MyStatus.LocalIP, inet_ntoa( sa.sin_addr));
4197
      MyStatus.LocalPort = ntohs( sa.sin_port);
4198
    }
4199
 
4200
    //get the remote IP-address and port number
4201
    len = sizeof( struct sockaddr_in);
4202
    pret = getpeername( GetSocket(), (struct sockaddr *)&sa, &len);
4203
    if (!pret)
4204
    {
4205
 
4206
      strcpy( MyStatus.RemoteIP, inet_ntoa( sa.sin_addr));
4207
      MyStatus.RemotePort = ntohs( sa.sin_port);
4208
    }
4209
  }
4210
 
4211
  //convert value to tag value
4212
  if (ConnectionTag.Type() != FL_MESSAGE) 
4213
  {
4214
 
4215
    if (ConnectionTag.Type() == FL_DIGITAL)   
4216
    {
4217
 
4218
      //tag type is dgitial, convert analog connection status to ON/OFF
4219
      switch( state)
4220
      {
4221
 
4222
        case DEVICE_CONNECTED:
4223
          state = 1; //connection status is ON
4224
          break;
4225
        default:
4226
          state = 0; //connection status is OFF
4227
          break;
4228
      }
4229
    }
4230
 
4231
    ConnectionTag = state;
4232
  }
4233
  else 
4234
    ConnectionTag = (char *)((LPCTSTR)theTask->Xlate( xl[ state]));
4235
 
4236
  //write the 'connection' tag
4237
  ConnectionTag.Write();
4238
}
4239
 
4240
 
4241
/////////////////////////////////////////////////////////////////////////////
4242
// Description: Update the status tag of the device
4243
// 
4244
// Parameter: 
4245
// 
4246
// Returns: 
4247
// 
4248
// Comment: 
4249
// 
4250
/////////////////////////////////////////////////////////////////////////////
4251
void CDeviceObject::UpdateStatus( int status)
4252
{
4253
 
4254
  //convert value to tag value
4255
  StatusTag = status;
4256
 
4257
  //write the 'connection' tag
4258
  StatusTag.Write();
4259
} //UpdateStatus
4260
 
4261
 
4262
/////////////////////////////////////////////////////////////////////////////
4263
// Description: This function is caled when the driver is stopping, and will
4264
// close all the receive sockets. A receive thread exits when its socket is
4265
// closed, and updates the count of registered sockets for the driver. 
4266
// This function will block until all the receive threads have ended and the 
4267
// number of registered receive sockets is zero.
4268
// Note that this function should be called after calling the CancelListen 
4269
// function. If receive threads are closed before th elisten is cancelled the
4270
// TM will try to reconnect, and succeed with the connection because the listen 
4271
// thread will accept the connection.
4272
// 
4273
// Parameter: 
4274
// 
4275
// Returns: 
4276
// 
4277
// Comment: 
4278
// 
4279
/////////////////////////////////////////////////////////////////////////////
4280
void MyFlTask::CancelReceiving( int wait)
4281
{
4282
 
4283
  int MaxWaitTime = 5000;  //wait 10 seconds at most
4284
  int SleepTime = 10;
4285
 
4286
 
4287
  //stop all driver parts
4288
  for (int i = 0; i < m_aDriver.GetSize(); i++)
4289
  {
4290
 
4291
    CDriverObject *driver = m_aDriver.GetAt( i);
4292
    CodeTrace( _T("RECV_COUNT"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, driver->GetReceiveSocketCount());
4293
 
4294
    //close all sockets for driver object
4295
    driver->CloseAllReceiveSockets();
4296
 
4297
    //wait until all 
4298
    for (int i = 0; i < MaxWaitTime/SleepTime; i++)
4299
    {
4300
 
4301
      if (driver->GetReceiveSocketCount()) FlSleep( 10);
4302
      else break;
4303
    }
4304
 
4305
    CodeTrace( _T("RECV_COUNT"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, driver->GetReceiveSocketCount());
4306
    int ret;
4307
 
4308
    //FlSleep( 5000);
4309
 
4310
    //timeout occurred?
4311
    if (driver->GetReceiveSocketCount())
4312
    {
4313
 
4314
      //there is a timeout, and there can be still threads active,
4315
      //threads which do have a connection are terminated
4316
      for (int i = 0; i < m_aDevice.GetSize(); i++)
4317
        if (m_aDevice.GetAt( i)->GetReceiveThread())
4318
        {
4319
 
4320
          ret = TerminateThread( m_aDevice.GetAt( i)->GetReceiveThread(), -1);
4321
          if (!ret) ret = GetLastError();
4322
          CodeTrace( _T("TERM_RECV"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, m_aDevice.GetAt( i)->GetName(), ret);
4323
        }
4324
    }
4325
  }
4326
} //CancelReceiving
4327
 
4328
 
4329
/////////////////////////////////////////////////////////////////////////////
4330
// Description: Get the number of TCP/IP packets for the specified dataset type
4331
// and length of the imx dataset. IMX  specifies a length of a dataset, the
4332
// message type determines how many data bytes are used for one field index, the 
4333
// function returns the number of packets the dirver has to send, to limit the 
4334
// reply to a maximum of 999 data bytes.
4335
// 
4336
// Parameter: len - IMX dataset length.
4337
// Parameter: type - IM-BAS protocl message type.
4338
// 
4339
// Returns: The number of packets for the specified message type with the given 
4340
// length.
4341
// 
4342
// Comment: 
4343
// 
4344
/////////////////////////////////////////////////////////////////////////////
4345
int MyFlTask::GetPacketCount(int len, int type)
4346
{
4347
 
4348
  int corr = 1; //correction factor, only used for strings
4349
 
4350
 
4351
  switch (type)
4352
  {
4353
 
4354
    case DS_COMMAND_CHAR:
4355
    case DS_PARAMETER_CHAR:
4356
    case DS_STATUS_CHAR:
4357
    case DS_STATINFO_CHAR:
4358
    case DS_STATDEL_CHAR: 
4359
    case DSW_COMMAND_CHAR:
4360
    case DSW_PARAMETER_CHAR:
4361
    case DSW_STATUS_CHAR:
4362
    case DSW_STATINFO_CHAR:
4363
    case DSW_STATDEL_CHAR: corr = PROT_STRING_SIZE/IMX_LONG_BND; break;
4364
  }
4365
 
4366
  int rep = (len / corr) / ImBasMaxLength( type);
4367
  int rest = (len / corr) % ImBasMaxLength( type);
4368
  if (rest != 0) rep++; //the minimum value for rep is 1
4369
 
4370
  return rep;
4371
} //GetPacketCount
4372
 
4373
 
4374
/////////////////////////////////////////////////////////////////////////////
4375
// Description: 
4376
// 
4377
// Parameter: *buf - Pointer to buffer to initialize. Value to initialise is 
4378
// set in the ini-file of the IM-BAS driver, and defaults to zero.
4379
// Parameter: len - length of the buffer to initialise, the length is given in
4380
// bytes.
4381
// Parameter: type - The type of the dataset, this type defines the boundary 
4382
// and data-type of the the dataset. With this type the converson of the initial
4383
// value is known: from integer to the data-type of the dataset. Normally the type
4384
// is directly retrieved form the received message an dhas on the values: 'B', 'I', 
4385
// 'L', 'R' or 'S'.
4386
// 
4387
// Returns: 
4388
// 
4389
// Comment: 
4390
// 
4391
/////////////////////////////////////////////////////////////////////////////
4392
void MyFlTask::ImBasInitImxData(char *buf, int len, char type)
4393
{
4394
 
4395
  int step = 1;
4396
  char value[4];
4397
  void *p = value;
4398
 
4399
 
4400
  //default is byte stream
4401
  value[0] = (char)GetNonExistentValue();
4402
 
4403
  switch (type)
4404
  {
4405
 
4406
    case 'I':
4407
      step = 2; 
4408
      *((int *)value) = (int)GetNonExistentValue();
4409
      break;
4410
 
4411
    case 'L': 
4412
      step = 4; 
4413
      *((long *)value) = (long)GetNonExistentValue();
4414
      break;
4415
 
4416
    case 'R':
4417
      step = 4; 
4418
      *((float *)value) = (float)GetNonExistentValue();
4419
      break;
4420
 
4421
    case 'S':
4422
      value[0] = 0;
4423
      break;
4424
  }
4425
 
4426
  //fill buffer
4427
  for (int i = 0; i < len; i += step)
4428
  {
4429
 
4430
    for( int k = 0; k < step; k++)
4431
      buf[ i + k] = value[ k];
4432
  }
4433
} //ImBasInitImxData
4434
 
4435
 
4436
/////////////////////////////////////////////////////////////////////////////
4437
// Description: Convert from UTC to local time, time is asumed to be of the 
4438
// form: hhmmss, that is six bytes. The ini-file of the IM-BAS driver has a 
4439
// key., which tells the driver to convert time from UTC to local (or not). The
4440
// time converted is the time in an exception message.
4441
// Just befor th etime th edate is assumed to be of the form: YYYYMMDD
4442
// 
4443
// Parameter: *buf - Buffer in which a six byte time is stored of the form:
4444
// hhmmss. This time is converted from UTC to local time.
4445
// 
4446
// Returns: 
4447
// 
4448
// Comment: 
4449
// 
4450
/////////////////////////////////////////////////////////////////////////////
4451
void MyFlTask::ImBasUtc2Local(char *buf)
4452
{
4453
 
4454
  //first check if conversion is needed
4455
  if (!ImBasUseLocalTime()) return;
4456
 
4457
  //conversion is needed, build utc time strucuture
4458
  SYSTEMTIME TmUTC, TmLocal;
4459
 
4460
  TmUTC.wYear = (buf[0] - '0') * 1000 + (buf[1] - '0') * 100 + (buf[2] - '0') * 10 + buf[3] - '0';
4461
  TmUTC.wMonth = (buf[4] - '0') * 10 + buf[5] - '0';
4462
  TmUTC.wDay = (buf[6] - '0') * 10 + buf[7] - '0';
4463
  TmUTC.wHour = (buf[8] - '0') * 10 + buf[9] - '0';
4464
  TmUTC.wMinute = (buf[10] - '0') * 10 + buf[11] - '0';
4465
  TmUTC.wSecond = (buf[12] - '0') * 10 + buf[13] - '0';
4466
  TmUTC.wMilliseconds = 0;
4467
  TmUTC.wDayOfWeek = -1; //undefined
4468
 
4469
  //convert utc --> local
4470
  SystemTimeToTzSpecificLocalTime( NULL, &TmUTC, &TmLocal);
4471
 
4472
  buf[0] = TmLocal.wYear / 1000;
4473
  buf[1] = (TmLocal.wYear % 1000) / 100;
4474
  buf[2] = (TmLocal.wYear % 100) / 10;
4475
  buf[3] = TmLocal.wYear % 10;
4476
  buf[4] = TmLocal.wMonth / 10;
4477
  buf[5] = TmLocal.wMonth % 10;
4478
  buf[6] = TmLocal.wDay / 10;
4479
  buf[7] = TmLocal.wDay % 10;
4480
  buf[8] = TmLocal.wHour / 10;
4481
  buf[9] = TmLocal.wHour % 10;
4482
  buf[10] = TmLocal.wMinute / 10;
4483
  buf[11] = TmLocal.wMinute % 10;
4484
  buf[12] = TmLocal.wSecond / 10;
4485
  buf[13] = TmLocal.wSecond % 10;
4486
 
4487
  //make ascii characters
4488
  for (int i = 0; i < 14; i++)
4489
    buf[ i] += '0';
4490
} //ImBasUtc2Local
4491
 
4492
 
4493
/////////////////////////////////////////////////////////////////////////////
4494
// Description: Convert from local time to UTC, time is asumed to be of the 
4495
// form: hhmmss, that is six bytes. The ini-file of the IM-BAS driver has a 
4496
// key. Which tells the driver to convert time from UTC to local (or not). The
4497
// time converted is the time in an exception message.
4498
// Just befor the time the date is assumed to be of the form: YYYYMMDD
4499
// 
4500
// Parameter: *buf - Buffer in which a six byte time is stored of the form:
4501
// hhmmss. This time is converted from UTC to local time.
4502
// 
4503
// Returns: 
4504
// 
4505
// Comment: 
4506
// 
4507
/////////////////////////////////////////////////////////////////////////////
4508
void MyFlTask::ImBasLocal2Utc(char *buf)
4509
{
4510
 
4511
  //first check if conversion is needed
4512
  if (ImBasUseLocalTime()) return;
4513
 
4514
  //conversion is needed, build local time strucuture
4515
  SYSTEMTIME TmUTC, TmLocal;
4516
  FILETIME FtUTC, FtLocal;
4517
  //TIME_ZONE_INFORMATION TmZone;
4518
 
4519
  TmLocal.wYear = (buf[0] - '0') * 1000 + (buf[1] - '0') * 100 + (buf[2] - '0') * 10 + buf[3] - '0';
4520
  TmLocal.wMonth = (buf[4] - '0') * 10 + buf[5] - '0';
4521
  TmLocal.wDay = (buf[6] - '0') * 10 + buf[7] - '0';
4522
  TmLocal.wHour = (buf[8] - '0') * 10 + buf[9] - '0';
4523
  TmLocal.wMinute = (buf[10] - '0') * 10 + buf[11] - '0';
4524
  TmLocal.wSecond = (buf[12] - '0') * 10 + buf[13] - '0';
4525
  TmLocal.wMilliseconds = 0;
4526
  TmLocal.wDayOfWeek = -1; //undefined
4527
 
4528
  //get local time zone
4529
  //GetTimeZoneInformation( &TmZone);
4530
 
4531
  //convert local --> utc
4532
  SystemTimeToFileTime( &TmLocal, &FtLocal);
4533
  LocalFileTimeToFileTime( &FtLocal, &FtUTC);
4534
  FileTimeToSystemTime( &FtUTC, &TmUTC);
4535
  //TzSpecificLocalTimeToSystemTime( &TmZone, &TmLocal, &TmUTC);
4536
 
4537
  buf[0] = TmUTC.wYear / 1000;
4538
  buf[1] = (TmUTC.wYear % 1000) / 100;
4539
  buf[2] = (TmUTC.wYear % 100) / 10;
4540
  buf[3] = TmUTC.wYear % 10;
4541
  buf[4] = TmUTC.wMonth / 10;
4542
  buf[5] = TmUTC.wMonth % 10;
4543
  buf[6] = TmUTC.wDay / 10;
4544
  buf[7] = TmUTC.wDay % 10;
4545
  buf[8] = TmUTC.wHour / 10;
4546
  buf[9] = TmUTC.wHour % 10;
4547
  buf[10] = TmUTC.wMinute / 10;
4548
  buf[11] = TmUTC.wMinute % 10;
4549
  buf[12] = TmUTC.wSecond / 10;
4550
  buf[13] = TmUTC.wSecond % 10;
4551
 
4552
  //make ascii characters
4553
  for (int i = 0; i < 14; i++)
4554
    buf[ i] += '0';
4555
} //ImBasLocal2Utc
4556
 
4557
 
4558
/////////////////////////////////////////////////////////////////////////////
4559
// Description: Clear RX-buffer, after the function call no message are left
4560
// in the input buffer.
4561
// 
4562
// Parameter: 
4563
// 
4564
// Returns: 
4565
// 
4566
// Comment: 
4567
// 
4568
/////////////////////////////////////////////////////////////////////////////
4569
void MyFlTask::ImBasPurgeRX( SOCKET sock)
4570
{
4571
 
4572
  int error;
4573
  FD_SET rfds;
4574
  TIMEVAL t = { 0, 0};
4575
  TIMEVAL *tval = NULL;
4576
  char buffer = 0;
4577
 
4578
 
4579
  //read all characters from input buffer
4580
  while (buffer != ImBasGetTerminator())
4581
  {
4582
 
4583
    //wait for data
4584
    FD_ZERO( &rfds);
4585
    FD_SET( sock, &rfds);
4586
    t.tv_sec = 0;
4587
    t.tv_usec = 0;
4588
    error = select( 0, &rfds, NULL, NULL, &t);
4589
 
4590
    if (!error || error == SOCKET_ERROR)
4591
    {
4592
 
4593
      //trace the winsock error
4594
      if (error == SOCKET_ERROR)
4595
        CodeTrace( _T("SOCKET_ERROR"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, WSAGetLastError());
4596
 
4597
      break;
4598
    }
4599
 
4600
    recv( sock, &buffer, 1, 0);
4601
  } 
4602
} //ImBasPurgeRX
4603
 
4604
 
4605
 
4606
/////////////////////////////////////////////////////////////////////////////
4607
// Description: Runtime manamger update function, error status is only set if
4608
// the error code is not blocked for displaying the error status. The error
4609
// status is blocked in the ini file of the module.
4610
// 
4611
// Parameter: 
4612
// 
4613
// 
4614
// Comment: 
4615
// 
4616
/////////////////////////////////////////////////////////////////////////////
4617
void MyFlTask::MyRunTimeManager( int ErrorCode, int Mode, char *Xlate, ...)
4618
{
4619
 
4620
  va_list vl;
4621
  char    buf[ 2*MAX_MSG];
4622
  char    *b = Xlate ? buf : NULL;
4623
 
4624
 
4625
  //check the mode, and reset to normal running if error is blocked
4626
  if ((ErrorCode > 0) && (ErrorCode <= MAX_ERROR))
4627
  {
4628
 
4629
    //check if error message is serious or just a warning
4630
    if (!m_iRunTimeError[ ErrorCode]) 
4631
    {
4632
 
4633
      Mode = (m_iPreviousState > FLS_INACTIVE) ? m_iPreviousState : FLS_ACTIVE;
4634
 
4635
   	  //give only message if the new mode will be error and not running
4636
	    if ((Mode == FLS_ACTIVE) && (m_iPreviousState == FLS_ERROR)) return;
4637
    }
4638
  }
4639
  else
4640
  {
4641
 
4642
    //keep current state
4643
    if (ErrorCode == 0) Mode = m_iPreviousState;
4644
  }
4645
 
4646
  //save previous mode
4647
  m_iPreviousState = Mode;
4648
 
4649
  //get the argument pointer
4650
  va_start( vl, Xlate);
4651
 
4652
  if (Xlate != NULL) vsprintf( buf, fl_xlate( Xlate), vl);
4653
  RunTimeManager( Mode, b);
4654
 
4655
  va_end( vl);
4656
} //MyRunTimeManager
4657
 
4658
 
4659
/////////////////////////////////////////////////////////////////////////////
4660
// Description: Check if a data value has limit restrictions set to it's value.
4661
// Calling this function will reset the error condition if present.
4662
// 
4663
// Parameter: 
4664
// 
4665
// Returns: A value not equal to zero is returned in case one or more data values
4666
// are change to their lower or upper limiot before sending them to the IM.
4667
// Otherwise zero is returned.
4668
// 
4669
// Comment: 
4670
// 
4671
/////////////////////////////////////////////////////////////////////////////
4672
int CDatasetObject::GetErrorOnLimit()
4673
{
4674
 
4675
	int x = theTask->GetErrorOnLimit() ? m_iLimitErrorActive: 0;
4676
	m_iLimitErrorActive = 0; 
4677
  return x;
4678
}
4679
 
4680
 
4681
/////////////////////////////////////////////////////////////////////////////
4682
// Description: Activate error on dataset caused by limiting a data value.
4683
// 
4684
// Parameter: 
4685
// 
4686
// Returns: 
4687
// 
4688
// Comment: 
4689
// 
4690
/////////////////////////////////////////////////////////////////////////////
4691
void CDatasetObject::SetErrorOnLimit() 
4692
{ 
4693
 
4694
  m_iLimitErrorActive = -1;
4695
}
4696
 
4697
 
4698
/////////////////////////////////////////////////////////////////////////////
4699
// Description: Calculate actual dataset length, by using the range definition.
4700
// 
4701
// Parameter: 
4702
// 
4703
// Returns: 
4704
// 
4705
// Comment: 
4706
// 
4707
/////////////////////////////////////////////////////////////////////////////
4708
void CDatasetObject::EvaluateRange() 
4709
{ 
4710
 
4711
  int iLen;
4712
  int i;
4713
  int s;
4714
  int t;
4715
  int k;
4716
  char *b;
4717
 
4718
  //remove leading and trailing spaces
4719
  m_sRange.TrimRight();
4720
  m_sRange.TrimLeft();
4721
  iLen = m_sRange.GetLength();
4722
 
4723
  //clear any previous array
4724
  if (m_iRange) free( m_iRange);
4725
  m_iRange = NULL;
4726
  m_iRangeLength = 0;
4727
  b = m_sRange.GetBuffer(1);
4728
 
4729
  for( i = 0, s = -1, t = -1; i <= iLen; i++)
4730
  {
4731
 
4732
    if ((b[i] >= '0') && (b[i] <= '9'))
4733
    {
4734
      if (s < 0) s = 0;
4735
      s = s * 10 + (b[i] - '0');
4736
    }
4737
    else
4738
    {
4739
 
4740
      //there is a range if the char is '-'
4741
      if (b[i] == '-')
4742
      {
4743
 
4744
        t = s;
4745
        s = -1;
4746
        continue;
4747
      }
4748
 
4749
      if ((t > -1) && (s > t))
4750
      {
4751
 
4752
        m_iRange = (short *)realloc( m_iRange, sizeof(short) * (m_iRangeLength + (s - t + 1)));       
4753
 
4754
        for( k = 0; k < (s - t + 1); k++)
4755
          m_iRange[ m_iRangeLength++] = t + k;
4756
 
4757
        s = -1;
4758
        t = -1;
4759
      }
4760
      else
4761
      {
4762
 
4763
        if (s < 0) continue;
4764
        //add only one short or id
4765
        m_iRange = (short *)realloc( m_iRange, sizeof(short) * (++m_iRangeLength));
4766
        m_iRange[ m_iRangeLength - 1] = s;
4767
        s = -1;
4768
        t = -1;
4769
      }
4770
    }
4771
  }
4772
 
4773
  //allocate for start and length of dataset
4774
  if (m_iRange == NULL) 
4775
  {
4776
 
4777
    m_iRangeLength = GetLength();
4778
    m_iRange = (short *)realloc( m_iRange, sizeof(short) * GetLength());
4779
 
4780
    for (i = 0; i < GetLength(); i++)
4781
      m_iRange[ i] = GetStart() + i;
4782
  }
4783
} //EvaluateRange
4784
 
4785
 
4786
/////////////////////////////////////////////////////////////////////////////
4787
// Description: Reset all the device information.
4788
// 
4789
// Parameter: 
4790
// 
4791
// Returns: 
4792
// 
4793
// Comment: 
4794
// 
4795
/////////////////////////////////////////////////////////////////////////////
4796
void CDeviceObject::ClearStatusVariables()
4797
{
4798
 
4799
  //initialise statusstructure
4800
  strcpy( MyStatus.Device, Name);
4801
  strcpy( MyStatus.LocalIP, "0.0.0.0");
4802
  strcpy( MyStatus.RemoteIP, "0.0.0.0");
4803
  MyStatus.LocalPort = 0;
4804
  MyStatus.RemotePort = 0;
4805
  MyStatus.Connection = 0;
4806
  for (int i = 0; i < 3; i++)
4807
  {
4808
 
4809
    MyStatus.Count[ i] = 0;
4810
    MyStatus.DataTime[ i] = 0;
4811
    MyStatus.WaitTime[ i] = 0;
4812
  }
4813
}
4814
 
4815
 
4816
////////////////////////////////////////////////////////////////////////////////
4817
//Description: Lock a deivce object, access to the object is granted to one 
4818
//thread only. Device-lock is released with the function 'Device->Release'.
4819
//
4820
//Parameter: 
4821
//
4822
//Returns:
4823
//
4824
//Comment:
4825
//
4826
////////////////////////////////////////////////////////////////////////////////
4827
void CDeviceObject::Lock()
4828
{
4829
  theTask->CodeTrace( _T("SEND_LOCK"), 5, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, GetName());
4830
  if (m_semWinSock) WaitForSingleObject( m_semWinSock, INFINITE);
4831
}
4832
 
4833
 
4834
////////////////////////////////////////////////////////////////////////////////
4835
//Description: Releaese a locked device, a device is locked with the function
4836
//'Device->Lock', after locking only one thread is granted access to the device.
4837
//This function releases a lock set on the device, note that any thread can 
4838
//release a lock set on the device. If a device needs to wait untill a present
4839
//lock is released (or no lock is placed on the deivce) the function 'Device->Lock'
4840
//should be used.
4841
//
4842
//Parameter: 
4843
//
4844
//Returns:
4845
//
4846
//Comment:
4847
//
4848
////////////////////////////////////////////////////////////////////////////////
4849
void CDeviceObject::Release()
4850
{
4851
 
4852
  theTask->CodeTrace( _T("RECV_LOCK"), 5, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, GetName());
4853
  if (m_semWinSock) ReleaseSemaphore( m_semWinSock, 1, NULL);
4854
}
4855
 
4856
////////////////////////////////////////////////////////////////////////////////
4857
//Description: 
4858
//
4859
//Parameter: 
4860
//
4861
//Returns:
4862
//
4863
//Comment:
4864
//
4865
////////////////////////////////////////////////////////////////////////////////
4866
CDeviceObject::~CDeviceObject()
4867
{
4868
 
4869
  theTask->CodeTrace( _T("DEV_DESTRUCT"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, GetName());
4870
 
4871
  //close and reset all semaphore handles  
4872
  for (int i = 0; i < FNC_COUNT; i++)
4873
  {
4874
    CloseHandle( m_semFunc[ i]);
4875
    //m_semFunc[ i] = NULL;
4876
  }
4877
 
4878
  CloseHandle( m_semWinSock);
4879
  CloseHandle( m_semImxDataset);
4880
 
4881
  //m_semWinSock = NULL;
4882
  //m_semImxDataset = NULL;
4883
} //CDeviceObject::~CDeviceObject()
4884
 
4885
 
4886
////////////////////////////////////////////////////////////////////////////////
4887
//Description: 
4888
//
4889
//Parameter: 
4890
//
4891
//Returns:
4892
//
4893
//Comment:
4894
//
4895
////////////////////////////////////////////////////////////////////////////////
4896
void CDriverObject::CloseAllReceiveSockets()
4897
{ 
4898
 
4899
  LockSockList();
4900
 
4901
  for (int i = 0; i < GetReceiveSocketCount(); i++)
4902
  {
4903
    closesocket( m_aRecvSockets.GetAt( i));
4904
    theTask->CodeTrace( _T("CLOSE_SOCK"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, m_aRecvSockets.GetAt( i), GetReceiveSocketCount());
4905
  }
4906
 
4907
  ReleaseSockList();
4908
} //CDriverObject::CloseAllReceiveSockets()
4909
 
4910
 
4911
////////////////////////////////////////////////////////////////////////////////
4912
//Description: 
4913
//
4914
//Parameter: 
4915
//
4916
//Returns:
4917
//
4918
//Comment:
4919
//
4920
////////////////////////////////////////////////////////////////////////////////
4921
void CDriverObject::RemoveReceiveSocket( SOCKET sock)
4922
{
4923
  int ret = -1;
4924
 
4925
 
4926
  LockSockList();
4927
 
4928
  int idx = FindReceiveSocket( sock, 0);
4929
 
4930
  theTask->CodeTrace( _T("REM_SOCK"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, sock, idx);
4931
  if ((idx >= 0) && (idx < m_aRecvSockets.GetSize()))
4932
    m_aRecvSockets.RemoveAt( idx);
4933
 
4934
  m_aRecvSockets.FreeExtra();
4935
 
4936
  ReleaseSockList();
4937
} //CDriverObject::RemoveReceiveSocket( SOCKET sock)
4938
 
4939
 
4940
////////////////////////////////////////////////////////////////////////////////
4941
//Description: 
4942
//
4943
//Parameter: 
4944
//
4945
//Returns:
4946
//
4947
//Comment:
4948
//
4949
////////////////////////////////////////////////////////////////////////////////
4950
int CDriverObject::AddReceiveSocket( SOCKET sock)
4951
{
4952
 
4953
  int ret = -1;
4954
 
4955
 
4956
  LockSockList();
4957
  ret = m_aRecvSockets.Add( sock);
4958
  theTask->CodeTrace( _T("ADD_SOCK"), 4, EVENTLOG_INFORMATION_TYPE, TRACE_TEXT, NULL, 0, sock, ret);
4959
  ReleaseSockList();
4960
  return ret;
4961
} //CDriverObject::AddReceiveSocket( SOCKET sock)
4962
 
4963
 
4964
////////////////////////////////////////////////////////////////////////////////
4965
//Description: 
4966
//
4967
//Parameter: 
4968
//
4969
//Returns:
4970
//
4971
//Comment:
4972
//
4973
////////////////////////////////////////////////////////////////////////////////
9 Marcel 4974
void CDeviceObject::Disconnect(SOCKET sock) 
1 mjordaan 4975
{
9 Marcel 4976
  int reset_sock = (sock == INVALID_SOCKET);
4977
 
4978
 
4979
  //get divce socket in case no parameter is given
4980
  if (reset_sock) sock = GetSocket();
4981
 
4982
  //reset socket in case we close device socket
4983
  reset_sock = (sock == GetSocket());
1 mjordaan 4984
 
4985
  theTask->CodeTrace( _T("DISCONN_SOCK"), 3, EVENTLOG_INFORMATION_TYPE, 
9 Marcel 4986
                      TRACE_TEXT, NULL, 0, sock, (LPCTSTR)GetName());
4987
  closesocket( sock);
1 mjordaan 4988
  ClearStatusVariables();
9 Marcel 4989
  if (reset_sock)
4990
    SetSocket( INVALID_SOCKET);
4991
};
1 mjordaan 4992
 
4993
 
4994
////////////////////////////////////////////////////////////////////////////////
4995
//Description: 
4996
//
4997
//Parameter: 
4998
//
4999
//Returns:
5000
//
5001
//Comment:
5002
//
5003
////////////////////////////////////////////////////////////////////////////////
5004
int CDeviceObject::GetTimeFormat()
5005
{
5006
 
5007
  return m_iTimeStamp;
5008
}
5009
 
5010
////////////////////////////////////////////////////////////////////////////////
5011
//Description: 
5012
//
5013
//Parameter: 
5014
//
5015
//Returns:
5016
//
5017
//Comment:
5018
//
5019
////////////////////////////////////////////////////////////////////////////////
5020
int MyFlTask::GetResponseTimeout()
5021
{
5022
 
5023
  return m_iResponseTimeout;
5024
}