[C con Clase] Codigo fuente de PLC Direct soft, como se hace un script fastAGI para que me controle las salidas del plc desde asterisk?

Jose Sanchez jsanchez.mercado en gmail.com
Dom Mayo 2 04:33:16 CEST 2010


Files included in this package:
readme.txt      - The file you are reading
intrface.c      - The file which should be changed to support a new
transport
hei.c           - Common source for HEI functions
hei.h           - Header for HEI functions
defs.h          - Defines used by hei.c
function.h      - Defines used by hei.c
/* Some usefull stuff! */
#if !defined(_DEFS_H)
#define _DEFS_H

typedef int  BOOL;
#define FALSE 0
#define TRUE 1

typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;

typedef unsigned int UINT;

#define LONG long
#define ULONG_MAX     0xffffffff    /* maximum unsigned long value */

#define LOBYTE(w) ((BYTE)(w))
#define HIBYTE(w) ((BYTE)(((UINT)(w) >> 8) & 0xFF))

#define LOWORD(l) ((WORD)(DWORD)(l))
#define HIWORD(l) ((WORD)((((DWORD)(l)) >> 16) & 0xFFFF))

#define MAKEWORD(a, b)      ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8))
#define MAKELONG(low, high) ((LONG)(((WORD)(low)) | (((DWORD)((WORD)(high)))
<< 16)))

#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))



#define NULL    ((void *)0)

#define TimeDiff(StartTime, EndTime)  (((DWORD)EndTime > (DWORD)StartTime) ?
((DWORD)EndTime - (DWORD)StartTime) : ((DWORD)EndTime + ((DWORD)ULONG_MAX -
(DWORD)StartTime) + 1))

#endif



#define UDP_PORT_ID  0x7070

#pragma pack(1)
typedef struct
 {
 char *pOSBegin;
 char *pOSEnd;
 char *pOSRun;
 WORD CRC;
 WORD BootSignature;
 WORD OSSignature;
 BYTE Unused[14];
 } OSDef;

/* Error/return val List */
#define HEI_NO_ERROR     0
#define ICMP_PKT_FOUND    65
#define ARP_PKT_FOUND    66
#define TYPE_NOT_HANDLED   67
#define LINK_SENSE_TRIGGERED  68
#define UNK_IP_PACKET    100
#define UNK_ETHERTYPE    101
#define UNK_PACKET_TYPE    102
#define UNK_802X_PACKET_TYPE  103
#define UNK_LLC_TYPE     104
#define CRC_DOES_NOT_MATCH   105
#define CRC_NO_DATA     106
#define ENET_ADDR_REPROGRAMMED 107
#define NULL_DATA_POINTER   108
#define SIZE_ERROR     109
#define NOT_FOUND      110
#define INVALID_TYPE     111
#define RAM_ALREADY_LOCKED   112
#define INVALID_REQUEST    113
#define TIMEOUT_ERROR    114
#define FLASH_PROGRAM_ERROR  115
#define INVALID_OS     116
#define INVALID_LOCATION   117
#define INVALID_SLOT_NUMBER  118
#define INVALID_DATA     119
#define MODULE_BUSY     120
#define CHANNEL_FAILURE    121
#define UNUSED_CHANNELS_EXIST  122
#define INVALID_UDP_PORT   123
#define SHUTDOWN_OS     124
#define NOT_MY_IP_ADDRESS   125
#define PROTECTION_ERROR   126
#define UNK_TYPE_ERROR    127
#define BACKPLANE_INIT_ERROR  128
#define UNK_RESPONSE     129
#define UNK_RXWX_FORMAT    130
#define UNK_ACK      131
#define UNK_NAK      132
#define RANGE_ERROR     133
#define LENGTH_WARNING    134
#define INVALID_BASE_NUMBER   135
#define INVALID_MODULE_TYPE   136
#define INVALID_OFFSET    137
#define INVALID_BOOT_VER_FOR_OS  138
#define BROKEN_TRANSMITTER   139
#define INVALID_ADDRESS    140
#define CHANNELS_UNUSED_0   200
#define CHANNELS_UNUSED_1   201
#define CHANNELS_UNUSED_2        201
#define CHANNELS_UNUSED_3        203
#define CHANNELS_UNUSED_4        204
#define CHANNELS_UNUSED_5        205
#define CHANNELS_UNUSED_6        206
#define CHANNELS_UNUSED_7        207
#define CHANNELS_UNUSED_8        208
#define CHANNELS_UNUSED_9        209
#define CHANNELS_UNUSED_10       210
#define CHANNELS_UNUSED_11       211
#define CHANNELS_UNUSED_12       212
#define CHANNELS_UNUSED_13       213
#define CHANNELS_UNUSED_14       214
#define CHANNELS_UNUSED_15       215
#define CHANNELS_UNUSED_16       216
#pragma pack()

/*
** HEI.C - Platform independent code for communicating with Host Automation
Products
**   line of ethernet modules.
**
** Copyright (C) - 1996-1997 Host Automation Products, Inc.
**
*/
#include "windows.h"
#include "defs.h"
#include <memory.h>
#include <string.h>
#include <ctype.h>
#include "hei.h"
void (*pAsyncPacketHandler)(HEIDevice *pDevice, BYTE *pResponse, int
ResponseLen) = 0;

/* Interface functions */
int HEIIOpen(void);
int HEIIClose(void);
int HEIIOpenDevice(HEITransport *pTransport, HEIDevice *pDevice);
int HEIICloseDevice(HEIDevice *pDevice);
int HEIIOpenTransport(HEITransport *pTransport);
int HEIICloseTransport(HEITransport *pTransport);
int HEIIReceivePacket(HEIDevice *pDevice, BYTE *pResponse, int
*pResponseSize);
int HEIISendPacket(HEIDevice *pDevice, BYTE *pPacket, WORD PacketSize);
DWORD HEIIGetCounter(void);
#define DEBUG_FILE 0
#if DEBUG_FILE
#include <stdio.h>
#include <stdarg.h>
#include "windows.h"
FILE *pOutFile=NULL;
void DebugString(char  *String, ...)
 {
 char  Buffer[200];
 va_list ap;
 va_start(ap, String);
 wvsprintf(Buffer, String, ap);
    //OutputDebugString(Buffer);
    pOutFile = fopen("c:\\heiout.txt", "a+");
 if (pOutFile)
  {
  fputs("\n", pOutFile);
  fputs(Buffer, pOutFile);
  fclose(pOutFile);
  }
 va_end(ap);
 }

#endif

__declspec(dllexport) int HEISetAsyncHandler(void (*pFun)(HEIDevice
*pDevice, BYTE *pResponse, int ResponseLen))
 {
 pAsyncPacketHandler = pFun;
 return 0;
 }
__declspec(dllexport) int HEIGetAsyncHandler(void (**pFun)(HEIDevice
*pDevice, BYTE *pResponse, int ResponseLen))
 {
 *pFun = pAsyncPacketHandler;
 return 0;
 }

/*
** This macro will return the difference between a start time (in
milliseconds) and an end time (also in milliseconds).
** It handles the fact that a DWORD millisecond indicator will wrap every
49.XXX days.
*/
#define TimeDiff(StartTime, EndTime)  (((DWORD)EndTime > (DWORD)StartTime) ?
((DWORD)EndTime - (DWORD)StartTime) : ((DWORD)EndTime + ((DWORD)ULONG_MAX -
(DWORD)StartTime) + 1))
#define WordDiff(Start, End)  (((WORD)End > (WORD)Start) ? ((WORD)End -
(WORD)Start) : ((WORD)End + ((WORD)0xFFFF - (WORD)Start) + 1))

#ifdef NOCRC
int DoCRC = 0;
#else
int DoCRC = 1;
#endif
#define EXTRA_TIME_FOR_SETUP_DATA 10
int DoEncrypt(Encryption *pEncrypt, BYTE *ptr, WORD Num);
__declspec(dllexport) int _SendPacket(HEIDevice *pDevice, BYTE *pPacket,
WORD PacketSize, BYTE *pResponse, int *pResponseSize, BOOL WaitForResponse,
BOOL ReturnWarnings);

#if defined(SUPERVISOR)
int PrepareSupervisorPacket(HEIDevice *pDevice, BYTE *pPacket, WORD
PacketSize);
#endif /* #if defined(SUPERVISOR) */

WORD CalcCRC(WORD    icrc, BYTE   *icp, WORD    icnt);

int InsertCRC(BYTE *pBuffer, WORD Len)
 {
 WORD *pWord = (WORD *) (pBuffer+5);

 if (DoCRC)
  {
  (*pWord) = CalcCRC(0, (BYTE *) (pBuffer+PACKET_HEADER_SIZE), (WORD) (Len -
PACKET_HEADER_SIZE));
  }
 else
  {
  (*pWord) = 0;
  }

 return 0;
 }
BOOL CRCCorrect(BYTE *pBuffer, WORD Len)
 {
 if (!DoCRC)
  return TRUE;
 else if (Len < PACKET_HEADER_SIZE)
  return FALSE;
 else
  {
  WORD *pCRC = (WORD *) (pBuffer+5);
  WORD CRC;
  if (!*pCRC)
   return TRUE;
  CRC = CalcCRC(0, (BYTE *) (pBuffer+PACKET_HEADER_SIZE), (WORD) (Len -
PACKET_HEADER_SIZE));
  return (CRC == (*pCRC));
  }
 }

/* int GetResponse(HEIDevice *pDevice, BYTE *pResponse, int *pResponseSize,
WORD ExtraTime=0, BOOL ProcessTimeout=TRUE, BOOL CheckAppVal=TRUE)*/
__declspec(dllexport) int GetResponse(HEIDevice *pDevice, BYTE *pResponse,
int *pResponseSize, WORD ExtraTime, BOOL ProcessTimeout, BOOL CheckAppVal)
 {
 unsigned short ThisAppVal = pDevice->LastAppVal;
 DWORD DeviceTimeout = pDevice->Timeout;
 int SavedSize = *pResponseSize;
 int Error;
 DWORD Timeout = DeviceTimeout + ExtraTime;
 DWORD StartTime = HEIIGetCounter();
 while (1)
  {
  *pResponseSize = SavedSize;
  Error = HEIIReceivePacket(pDevice, pResponse, pResponseSize);

  if (!Error && (*pResponseSize))
   {
   /* We have a packet to look at. */
   /* Check the App Val. */
   WORD *pWord = (WORD *) (pResponse+3);

   if (*pWord == ThisAppVal || !ThisAppVal || !CheckAppVal)
    {
    int Retval;

    if (!CheckAppVal)
     pDevice->LastAppVal = *pWord;
    Retval = 0;
    if (CRCCorrect((BYTE *) pResponse, (WORD) *pResponseSize))
     {
     /* We have our response! */
     }
    else
     {
     pDevice->BadCRCCount++;
     Retval =  HEIE_CRC_MISMATCH;
     }

    return Retval;
    }
   else
    {
    if (pAsyncPacketHandler)
     {
     (*pAsyncPacketHandler)(pDevice, pResponse, *pResponseSize);
     }
    pDevice->LatePacketCount++;
    continue;
    }
   }
  else if (Error && Error != HEIE_NO_RESPONSE)
   {
   return Error;
   }
  else if (!ProcessTimeout)
   {
   /* No more packets to look at. */
   return HEIE_NO_RESPONSE;
   }

  if (ProcessTimeout && (TimeDiff(StartTime, HEIIGetCounter()) >= Timeout))
   {
   /* Timeout! */
   break;
   }
  }

 *pResponseSize = 0;
 return HEIE_TIMEOUT;
 }

static unsigned short AppVal = 1;
__declspec(dllexport) int HEIGetResponse(HEIDevice *pDevice, BYTE
*pResponse, int *pResponseSize, BOOL CheckAppVal)
 {
 int Retval;

#if DEBUG_FILE
 DebugString("In GetResponse %u", AppVal);
#endif
 Retval = GetResponse(pDevice, pResponse, pResponseSize, 0, FALSE,
CheckAppVal);

#if DEBUG_FILE
 DebugString("Leaving GetResponse %u -> %d (0x%X)", AppVal, Retval, Retval);
#endif
 return Retval;
 }

int WriteERMCommandData(HEIDevice *pDevice, WORD Base, WORD Slot, BYTE
*pData, WORD NumBytes, WORD Offset)
 {
 return HEIWriteERMData(pDevice, Base, Slot, DATA_COMMAND, pData, NumBytes,
Offset);
 }
int ReadERMCommandData(HEIDevice *pDevice, WORD Base, WORD Slot, BYTE
*pData, WORD NumBytes, WORD Offset)
 {
 return HEIReadERMData(pDevice, Base, Slot, DATA_COMMAND, pData, NumBytes,
Offset);
 }

#if HEIAPIVERSION>=3
int _SendProxyPacket(HEIDevice *pDevice, BYTE *pPacket, WORD PacketSize,
BYTE *pResponse, int *pResponseSize, BOOL WaitForResponse, BOOL
ReturnWarnings)
 {
 int Retval = 0;
 WORD DataOffset = pDevice->DataOffset;
 WORD SubTotal = PacketSize - DataOffset;
 BYTE *pCmd = pPacket+PacketSize-SubTotal;
 // Disable proxying.
 pDevice->UseProxy = FALSE;
 Retval = WriteERMCommandData(pDevice, pDevice->ProxyBase,
pDevice->ProxySlot, pCmd, SubTotal, 0);
 if (Retval)
  {
 // printf("\nError %d (0x%X) from WriteERMCommandData", Retval, Retval);
  }
 else
  {
  BYTE Extra[10];
  WORD ExtraLen;
  WORD *pWord;
  pWord = (WORD *) &Extra[0];
  *pWord++ = pDevice->ProxyDevNum;
  *pWord++ = 0;  // CmdOffset
  *pWord++ = SubTotal;  // CmdLength
  *pWord++ = 0;  // RspOffset;
  *pWord++ = 0x800; // RspLength
  ExtraLen = 10;
  Retval = HEIDoERMCommandEx(pDevice, pDevice->ProxyBase,
pDevice->ProxySlot, COMMAND_PROCESS_COMMAND_BUFFER, Extra, ExtraLen);
  if (Retval)
   {
 //  printf("Error %d (0x%X) from call to WPLCDoERMCommandEx", Retval,
Retval);
   }
  else
   {
   // Read response from command buffer.
   BYTE ResponseBuffer[4];
   Retval = ReadERMCommandData(pDevice, pDevice->ProxyBase,
pDevice->ProxySlot, ResponseBuffer, 4, 0);
   if (Retval)
    {
 //   printf("\nError %d (0x%X) from ReadERMCommandData", Retval, Retval);
    }
   else
    {
    WORD *pError = (WORD *) &ResponseBuffer[0];
    WORD *pLen = (WORD *) &ResponseBuffer[2];
    if (*pError)
     {
 //    printf("\nCommand Error: %d  Len: %d", *pError, *pLen);
     }
    else
     {
     Retval = ReadERMCommandData(pDevice, pDevice->ProxyBase,
pDevice->ProxySlot, pResponse+PACKET_HEADER_SIZE, *pLen, 4);
     if (Retval)
      {
 //     printf("\nError %d (0x%X) from ReadERMCommandData", Retval, Retval);
      }
     else
      {
      // Fix pResponse[0] - pResponse[PACKET_HEADER_SIZE-1]
      (*pResponseSize) = (*pLen) + PACKET_HEADER_SIZE;
      }
     }
    }
   }
  }
 // Reenable proxying.
 pDevice->UseProxy = TRUE;
 return Retval;
 }
#endif

/*int SendPacket(HEIDevice *pDevice, BYTE *pPacket, WORD PacketSize, BYTE
*pResponse, int *pResponseSize, BOOL WaitForResponse=TRUE, BOOL
ReturnWarnings=FALSE)*/
__declspec(dllexport) int _SendPacket(HEIDevice *pDevice, BYTE *pPacket,
WORD PacketSize, BYTE *pResponse, int *pResponseSize, BOOL WaitForResponse,
BOOL ReturnWarnings)
 {
#if HEIAPIVERSION>=3
 if (pDevice->UseProxy == TRUE)
  {
  // Proxy this command to the device.
  //printf("\nUse proxy.");
  return _SendProxyPacket(pDevice, pPacket, PacketSize, pResponse,
pResponseSize, WaitForResponse, ReturnWarnings);
  }
#endif
  {
  BYTE *ptr;
  WORD *pWord;
  unsigned short ThisAppVal;
  unsigned short *pWordAppVal;
  BYTE *pBegin = pPacket;
  WORD PreHeaderBytes = pDevice->DataOffset - PACKET_HEADER_SIZE;
  WORD Retry;
  if (pDevice->UseAddressedBroadcast)
   PreHeaderBytes -= 7;

  pPacket += PreHeaderBytes;

  ptr = pPacket;

  if (pDevice->UseAddressedBroadcast)
   {
   pPacket[PACKET_HEADER_SIZE] = FUN_ADDRESSED_BROADCAST;
   memcpy(&pPacket[PACKET_HEADER_SIZE+1], pDevice->ENetAddress, 6);
   }

  *ptr++ = 'H';
  *ptr++ = 'A';
  *ptr   = 'P';

  /* Calculate CRC */
  InsertCRC(pPacket, (WORD) (PacketSize-PreHeaderBytes));

  /* Insert the number of bytes which were checksumed. */
  pWord = (WORD *) (pPacket+7);

  *pWord = (WORD) PacketSize - PreHeaderBytes - PACKET_HEADER_SIZE; /* This
is the bytes to follow/checksum */

  /* Do encryption (if required) */
  if (pDevice->_pTransport->Encrypt.Algorithm)
   DoEncrypt(&pDevice->_pTransport->Encrypt, pPacket+5, (WORD)
(PacketSize-5-PreHeaderBytes));

  pWordAppVal = (unsigned short *) (pPacket+3);


 #if defined(SUPERVISOR)
  PrepareSupervisorPacket(pDevice, pPacket, PacketSize);
 #endif /* #if defined(SUPERVISOR) */
  for (Retry = 0; Retry<=pDevice->Retrys; Retry++)
      {
   int ResponseSize = *pResponseSize;
   int Error;

   ThisAppVal = AppVal++;
   pDevice->LastAppVal = ThisAppVal;

   if (!AppVal)
    AppVal++;

   if (Retry)
    pDevice->RetryCount++;

   /* Insert the app value. */
   *pWordAppVal = ThisAppVal;

   Error = HEIISendPacket(pDevice, pBegin, PacketSize);

   if (Error)
    {
    *pResponseSize = 0;
    return Error;
    }

   if (!WaitForResponse)
    {
    *pResponseSize = 0;
    return HEIE_NO_RESPONSE;
    }
   Error = GetResponse(pDevice, pResponse, &ResponseSize, 0, TRUE, TRUE);
   if (!Error)
    {
    *pResponseSize = ResponseSize;
    if (Retry != 0 && ReturnWarnings)
     return HEIW_RETRY;
    return 0;   /* Success! */
    }
   else if (Error != HEIE_TIMEOUT)
    return Error;
   }

  *pResponseSize = 0;
  return HEIE_TIMEOUT;
  }
 }

__declspec(dllexport) int SendPacketTwoResponses(HEIDevice *pDevice, BYTE
*pPacket, WORD PacketSize, BYTE *pResponse, int *pResponseSize,
         BOOL WaitForResponse, BOOL ReturnWarnings, WORD Bytes2Verify, BYTE
*pVerifyData,
         WORD ExtraTime, BOOL ProcessTimeout, BOOL CheckAppVal)
 {
 WORD SaveRetryCount = pDevice->RetryCount;
 WORD SaveRetrys = pDevice->Retrys;
 int SaveResponseSize = *pResponseSize;
#if HEIAPIVERSION>=3
 if (pDevice->UseProxy == TRUE)
  {
  // Proxy this command to the device.
  //printf("\nUse proxy.");
  return _SendProxyPacket(pDevice, pPacket, PacketSize, pResponse,
pResponseSize, WaitForResponse, ReturnWarnings);
  }
#endif
 while (TRUE)
  {
  int Error = _SendPacket(pDevice, pPacket, PacketSize,pResponse,
pResponseSize, WaitForResponse, ReturnWarnings);
  if (Error && !(Error & HEIW_FIRST_WARNING))
   {
   /* Restore retrys value */
   pDevice->Retrys = SaveRetrys;
   return Error;
   }
  /* Check and make sure we got an ack. */
  if (Bytes2Verify)
   {
   BYTE *pRet = (pResponse+PACKET_HEADER_SIZE);

   while (Bytes2Verify)
    {
    if (*pRet++ != *pVerifyData++)
     {
     /* Restore retrys value */
     pDevice->Retrys = SaveRetrys;
     return HEIE_INVALID_RESPONSE;
     }
    Bytes2Verify--;
    }
   }
  /* Restore size of response buffer. */
  *pResponseSize = SaveResponseSize;
  Error = GetResponse(pDevice, pResponse, pResponseSize, ExtraTime,
ProcessTimeout, CheckAppVal);
  if (Error == HEIE_TIMEOUT)
   {
   WORD TotalRetrys;
   /* Perform a retry */
   pDevice->RetryCount++;
   /* See how many retrys we have already done. */
   TotalRetrys = WordDiff(SaveRetryCount, pDevice->RetryCount);
   if (TotalRetrys >= SaveRetrys)
    {
    /* Restore retrys value */
    pDevice->Retrys = SaveRetrys;
    return Error;
    }
   /* Prepare to go again. */
   *pResponseSize = SaveResponseSize;
   /* Adjust number of retrys left to do. */
   pDevice->Retrys = SaveRetrys - TotalRetrys;
   }
  else
   {
   /* Restore retrys value */
   pDevice->Retrys = SaveRetrys;
   if (!Error && pDevice->RetryCount != SaveRetryCount)
    Error = HEIW_RETRY;
   if (Error)
    return Error;
   return HEIE_NULL;
   }
  }
 }

/* Transport Stuff */
__declspec(dllexport) int HEIOpenTransport(HEITransport *pTransport, WORD
Ver, ENetAddress *pSourceAddress)
/* __declspec(dllexport) int HEIOpenTransport(HEITransport *pTransport, WORD
Ver, DWORD NetworkAddress)*/
 {
 int Retval;

#if DEBUG_FILE
 DebugString("In HEIOpenTransport");
#endif
 if (HEIAPIVERSION != Ver)
  return HEIE_VER_MISMATCH;
 if (!pTransport)
  return HEIE_NULL_TRANSPORT;

 pTransport->Encrypt.Algorithm = HEIEN_NONE;
 /*pTransport->NetworkAddress = NetworkAddress;*/
 pTransport->pSourceAddress = pSourceAddress;

 Retval = HEIIOpenTransport(pTransport);

#if DEBUG_FILE
 DebugString("Leaving HEIOpenTransport", Retval);
#endif

 return Retval;
 }


__declspec(dllexport) int HEICloseTransport(HEITransport *pTransport)
 {
 if (!pTransport)
  return HEIE_NULL_TRANSPORT;

 return HEIICloseTransport(pTransport);
 }
__declspec(dllexport) int HEIOpenDevice
  (
  HEITransport *pTransport,
  HEIDevice *pDevice,
  WORD Ver,
  WORD iTimeout,
  WORD iRetrys,
  BOOL UseBroadcast
  )
 {
 int Retval;

#if 0
  {
  char Buffer[200];
  wsprintf(Buffer, "Timeout: %d  Retrys: %d  UseBroadCast: %d", iTimeout,
iRetrys, UseBroadcast);
  MessageBox(NULL, Buffer, "HEIOpenDevice", 0);
  }
#endif

#if DEBUG_FILE
 DebugString("In HEIOpenDevice");
#endif

 if (HEIAPIVERSION != Ver)
  return HEIE_VER_MISMATCH;
 if (!pTransport)
  return HEIE_NULL_TRANSPORT;

 if (!pDevice)
  return HEIE_INVALID_DEVICE;
 pDevice->_dwParam    = 0;
 pDevice->Timeout    = iTimeout;
 pDevice->Retrys    = iRetrys;
 pDevice->UseAddressedBroadcast = UseBroadcast;
 pDevice->UseBroadcast  = UseBroadcast;
 pDevice->pData     = 0;
 pDevice->SizeOfData   = 0;
 pDevice->DataOffset   = PACKET_HEADER_SIZE;
 pDevice->pBuffer    = 0;
 pDevice->RetryCount   = 0;
 pDevice->BadCRCCount   = 0;
 pDevice->LatePacketCount = 0;
 pDevice->ParallelPackets = FALSE;
 pDevice->_pTransport = pTransport;
#if HEIAPIVERSION==3
 pDevice->UseProxy = 0;
 pDevice->ProxyBase = 0;
 pDevice->ProxySlot = 0;
 pDevice->ProxyDevNum = 0;
 memset(pDevice->Reserved, 0, sizeof(pDevice->Reserved));  /* Reserved
bytes, set to zero */
#endif
 if (pDevice->UseAddressedBroadcast)
  pDevice->DataOffset += 7;
 Retval = HEIIOpenDevice(pTransport, pDevice);

#if DEBUG_FILE
 DebugString("Leaving HEIOpenDevice", Retval);
#endif
 return Retval;
 }
__declspec(dllexport) int HEICloseDevice(HEIDevice *pDevice)
 {
 int Retval = HEIE_NULL;
 if (!pDevice)
  return HEIE_INVALID_DEVICE;

 if (pDevice->_pTransport)
  {
  Retval = HEIICloseDevice(pDevice);
  pDevice->_pTransport = (HEITransport *) NULL;
  }

 return Retval;
 }

__declspec(dllexport) int HEIOpen(WORD Ver)
 {
 if (HEIAPIVERSION != Ver)
  return HEIE_VER_MISMATCH;

 return HEIIOpen();
 }
__declspec(dllexport) int HEIClose()
 {
 return HEIIClose();
 }

int DoEncrypt(Encryption *pEncrypt, BYTE *ptr, WORD Num)
 {
 switch (pEncrypt->Algorithm)
  {
  case 1:  /* Private key encryption (XOR) */
   {
   BYTE *keyptr = pEncrypt->Key;
   WORD x;

   for (x=0; x<Num; x++)
    {
    *ptr++ ^= *keyptr++;

    if (!*keyptr)
     keyptr = pEncrypt->Key;
    }

   return 0;
   }

  default:
   return -1;
  }
 }
int OpenQueryableDevice(HEITransport *pTransport, HEIDevice *pDevice, WORD
Ver)
 {
 /* Open a device which I can use for broadcasting a packet. */
 int RetVal = HEIOpenDevice(pTransport, pDevice, Ver, 20, 0, TRUE);
 if (!RetVal)
  {
  pDevice->UseAddressedBroadcast = FALSE;    /* Don't want to use
'Addressed' Broadcast, just Broadcast! */
  pDevice->DataOffset -= 7;  /* We are not using addressed broadcast. */
  pDevice->wParam = 0;
  }
 return RetVal;
 }


DWORD QueryTimeout = 600;
__declspec(dllexport) DWORD HEISetQueryTimeout(DWORD NewTimeout)
 {
 DWORD Save = QueryTimeout;
 QueryTimeout = NewTimeout;
 return Save;
 }
__declspec(dllexport) DWORD HEIGetQueryTimeout()
 {
 return QueryTimeout;
 }

int DoQuery(HEITransport *pTransport, HEIDevice *pDevice, HEIDevice
*pDevices, WORD *pNumDevices, WORD Ver, BYTE *pBuffer, WORD BufferSize)
 {
 BYTE RetBuffer[600];
 int ResponseSize = sizeof(RetBuffer);
 BYTE FromAddress[20];
 int Error;
 WORD Count = 0;
 DWORD Timeout = QueryTimeout;
 DWORD StartTime;
 int Retval;
 pDevice->pData = FromAddress;
 pDevice->SizeOfData = sizeof(FromAddress);
 Error = _SendPacket(pDevice, pBuffer, BufferSize, RetBuffer, &ResponseSize,
TRUE, FALSE);
 StartTime = HEIIGetCounter();
 Retval = HEIE_NULL;
 while (1)
  {
  switch ((WORD) Error)
   {
   case HEIE_NULL:
    {
    /* No Error, so process packet. */
    if (RetBuffer[0] == 'H' && RetBuffer[1] == 'A' && (RetBuffer[2] == 'P'
|| RetBuffer[2] == 'A') &&
     RetBuffer[PACKET_HEADER_SIZE] == 0x55 &&
     (BYTE) RetBuffer[PACKET_HEADER_SIZE+1] == 0xAA)
     {
     if (Count < (*pNumDevices))
      {
      memcpy(pDevices[Count].Address.Raw, pDevice->pData,
pDevice->SizeOfData);
      memcpy(pDevices[Count].ENetAddress, (char *)
(RetBuffer+PACKET_HEADER_SIZE+2), 6);
      if (pTransport->Protocol == HEIP_IP)
       {
       if (RetBuffer[PACKET_HEADER_SIZE+8] == 1)
        pDevices[Count].Address.Raw[19] = 1; /* The modules IP address is
not initialized. */
       else
        pDevices[Count].Address.Raw[19] = 0;
       }
      Count++;
      }
     else
      {
      Count++;
      Retval = HEIE_BUFFER_TOO_SMALL;
      }
     }
    break;
    }
   case HEIE_TIMEOUT:
    break;

   case HEIW_RETRY:
    break;
   default:
    {
    /* Other error, so bail out. */
    pDevice->pData = 0;
    pDevice->SizeOfData = 0;
    return Error;
    }
   }
  if (TimeDiff(StartTime, HEIIGetCounter()) < Timeout)
   {
   ResponseSize = sizeof(RetBuffer);
   pDevice->SizeOfData = sizeof(FromAddress);
   Error = GetResponse(pDevice, RetBuffer, &ResponseSize, 0, TRUE, TRUE);
   }
  else
   break;
  }
 *pNumDevices = Count;
 pDevice->pData = 0;
 pDevice->SizeOfData = 0;
 return Retval;
 }

__declspec(dllexport) int HEIQueryDevices(HEITransport *pTransport,
HEIDevice *pDevices, WORD *pNumDevices, WORD Ver)
 {
 HEIDevice qDevice;
 WORD DataOffset;
 BYTE Buffer[100];
 WORD Total;
 int Retval;
 int Error;
 if (pTransport->Protocol == HEIP_SERIAL)
  {
  *pNumDevices = 0;
  return HEIE_NULL;
  }
 Error = OpenQueryableDevice(pTransport, &qDevice, Ver);

 if (Error)
  return Error;
 /* Build the buffer.   */
 DataOffset = qDevice.DataOffset;
 Buffer[DataOffset] = FUN_POLLING_ALL;   /* This is the function code! */
 Total = DataOffset+1;
 Retval = DoQuery(pTransport, &qDevice, pDevices, pNumDevices, Ver, Buffer,
Total);
 HEICloseDevice(&qDevice);

 return Retval;
 }
__declspec(dllexport) int HEIQueryDeviceData(HEITransport *pTransport,
HEIDevice *pDevices, WORD *pNumDevices, WORD Ver, WORD DataType, BYTE
*pData, WORD SizeofData)
 {
 HEIDevice qDevice;
 WORD DataOffset;
 BYTE Buffer[600];
 WORD *pWord;
 WORD Total;
 int Retval;

 int Error = OpenQueryableDevice(pTransport, &qDevice, Ver);

 if (Error)
  return Error;
 /* Build the buffer.   */
 DataOffset = qDevice.DataOffset;
 Buffer[DataOffset] = FUN_QUERY_SETUP_DATA;   /* This is the function code!
*/
 Buffer[DataOffset+1] = 0;
 pWord = (WORD *) (Buffer+DataOffset+2);

 if (SizeofData > 512)
   SizeofData = 512;
 *pWord++ = DataType;
 *pWord = SizeofData;

 memcpy(Buffer+DataOffset+6, pData, SizeofData);
 Total = qDevice.DataOffset+6+SizeofData;
 Retval = DoQuery(pTransport, &qDevice, pDevices, pNumDevices, Ver, Buffer,
Total);
 HEICloseDevice(&qDevice);

 return Retval;
 }

/* SUPPORT INFORMATION */
__declspec(dllexport) int HEIReadSupportInfo(HEIDevice *pDevice, BYTE
*pSupportInfo, WORD SizeOfSupportInfo)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int NumBytes;
 int Error;
 int Retval;
 Buffer[DataOffset] = (BYTE) FUN_READ_SUPPORT_INFO;    /* This is the
function code! */
 Total = DataOffset+1;
 NumBytes = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  NumBytes -= PACKET_HEADER_SIZE;
  if ((WORD) NumBytes > SizeOfSupportInfo)
   {
   Retval = HEIE_BUFFER_TOO_SMALL;
   NumBytes = SizeOfSupportInfo;
   }
  memcpy(pSupportInfo, RetBuffer+PACKET_HEADER_SIZE, NumBytes);
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;
  }
 return Retval;
 }

/* VERSION INFORMATION */
__declspec(dllexport) int HEIReadVersionInfo(HEIDevice *pDevice, BYTE
*pVerInfo, WORD SizeVerInfo)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;
 Buffer[DataOffset] = (BYTE) FUN_READ_VER_INFO;    /* This is the function
code! */
 Total = DataOffset+1;
 NumBytes = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  NumBytes -= PACKET_HEADER_SIZE;
  if ((WORD) NumBytes > SizeVerInfo)
   {
   Retval = HEIE_BUFFER_TOO_SMALL;
   NumBytes = SizeVerInfo;
   }
  memcpy(pVerInfo, RetBuffer+PACKET_HEADER_SIZE, NumBytes);
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;
  }
 return Retval;
 }

/* BASE DEFINITION */
__declspec(dllexport) int HEIReadBaseDef(HEIDevice *pDevice, BYTE
*pBaseDefInfo, WORD *pSizeOfBaseDefInfo)
 {
 BYTE Buffer[300];
 BYTE RetBuffer[1000];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;
 Buffer[DataOffset] = FUN_READ_BASE_DEF;    /* This is the function code! */
 Total = DataOffset+1;
 if (pBaseDefInfo && *pBaseDefInfo == 0xB1)
  {
  Buffer[DataOffset+1] = *pBaseDefInfo;
  Total++;
  }
 NumBytes = sizeof(RetBuffer);
 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  NumBytes -= PACKET_HEADER_SIZE;
  if ((WORD) NumBytes > *pSizeOfBaseDefInfo)
   {
   Retval = HEIE_BUFFER_TOO_SMALL;
   NumBytes = *pSizeOfBaseDefInfo;
   }
  memcpy(pBaseDefInfo, RetBuffer+PACKET_HEADER_SIZE, NumBytes);
  (*pSizeOfBaseDefInfo) = NumBytes;
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;
  (*pSizeOfBaseDefInfo) = 0;
  }
 return Retval;
 }
__declspec(dllexport) int HEIRescanBase(HEIDevice *pDevice, DWORD Flags,
BYTE *pBaseDefInfo, WORD *pSizeOfBaseDefInfo)
 {
 BYTE Buffer[300];
 BYTE RetBuffer[1000];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;
 DWORD *pDWord;
 Buffer[DataOffset] = FUN_INIT_BASE_DEF;    /* This is the function code! */
 pDWord = (DWORD *) &Buffer[DataOffset+1];
 *pDWord = Flags;
 Total = DataOffset+5;
 NumBytes = sizeof(RetBuffer);
 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  NumBytes -= PACKET_HEADER_SIZE;
  if ((WORD) NumBytes > *pSizeOfBaseDefInfo)
   {
   Retval = HEIE_BUFFER_TOO_SMALL;
   NumBytes = *pSizeOfBaseDefInfo;
   }
  memcpy(pBaseDefInfo, RetBuffer+PACKET_HEADER_SIZE, NumBytes);
  (*pSizeOfBaseDefInfo) = NumBytes;
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;
  (*pSizeOfBaseDefInfo) = 0;
  }
 return Retval;
 }
__declspec(dllexport) int HEIInitBaseDef(HEIDevice *pDevice, BYTE
*pBaseDefInfo, WORD *pSizeOfBaseDefInfo)
 {
 BYTE Buffer[300];
 BYTE RetBuffer[600];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;
 Buffer[DataOffset] = FUN_INIT_BASE_DEF;    /* This is the function code! */
 Total = DataOffset+1;
 NumBytes = sizeof(RetBuffer);
 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  NumBytes -= PACKET_HEADER_SIZE;
  if ((WORD) NumBytes > *pSizeOfBaseDefInfo)
   {
   Retval = HEIE_BUFFER_TOO_SMALL;
   NumBytes = *pSizeOfBaseDefInfo;
   }
  memcpy(pBaseDefInfo, RetBuffer+PACKET_HEADER_SIZE, NumBytes);
  (*pSizeOfBaseDefInfo) = NumBytes;
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;
  (*pSizeOfBaseDefInfo) = 0;
  }
 return Retval;
 }
__declspec(dllexport) int HEIWriteBaseDef(HEIDevice *pDevice, BYTE
*pInputBaseDef, WORD SizeOfInputBaseDef, BYTE *pOutputBaseDef, WORD
*pSizeOfOutputBaseDef)
 {
 BYTE Buffer[600];
 BYTE RetBuffer[600];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;
 WORD *pWord;
 Buffer[DataOffset] = FUN_WRITE_BASE_DEF;    /* This is the function code!
*/
 Buffer[DataOffset+1] = 0;

 pWord = (WORD *) &Buffer[DataOffset+2];
 *pWord = SizeOfInputBaseDef;
 Total = DataOffset+4+SizeOfInputBaseDef;
 if (Total > sizeof(Buffer))
  {
  return HEIE_DATA_TOO_LARGE;
  }

 memcpy(Buffer+DataOffset+4, pInputBaseDef, SizeOfInputBaseDef);

 NumBytes = sizeof(RetBuffer);
 Error = SendPacketTwoResponses(pDevice, Buffer, Total, RetBuffer,
&NumBytes,
         TRUE, FALSE,
         0, NULL,
         30000, TRUE, TRUE);

#if 0
 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;

 NumBytes = sizeof(RetBuffer);
 Error = GetResponse(pDevice, RetBuffer, &NumBytes, 30000, TRUE, TRUE);
#endif
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;

 Retval = Error;
 if (NumBytes)
  {
  short int *pInt = (short int *) (RetBuffer+PACKET_HEADER_SIZE);

  if (*pInt)
   Retval = *pInt;
  else if (pOutputBaseDef)
   {
   NumBytes -= (PACKET_HEADER_SIZE+2);

   if ((WORD) NumBytes > *pSizeOfOutputBaseDef)
    {
    Retval = HEIE_BUFFER_TOO_SMALL;
    NumBytes = *pSizeOfOutputBaseDef;
    }

   memcpy(pOutputBaseDef, RetBuffer+PACKET_HEADER_SIZE+2, NumBytes);
   (*pSizeOfOutputBaseDef) = NumBytes;
   }
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;

  if (pOutputBaseDef && pSizeOfOutputBaseDef)
   (*pSizeOfOutputBaseDef) = 0;
  }
 return Retval;
 }
/* DEVICE DEFINITION */
__declspec(dllexport) int HEIReadDeviceDef(HEIDevice *pDevice, BYTE
*pDeviceDefInfo, WORD SizeOfDeviceDefInfo)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;
 Buffer[DataOffset] = (BYTE) FUN_READ_DEVICE_INFO;    /* This is the
function code! */
 Total = DataOffset+1;
 NumBytes = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;

 if (NumBytes)
  {
  NumBytes -= PACKET_HEADER_SIZE;
  if ((WORD) NumBytes > SizeOfDeviceDefInfo)
   {
   Retval = HEIE_BUFFER_TOO_SMALL;
   NumBytes = SizeOfDeviceDefInfo;
   }
  memcpy(pDeviceDefInfo, RetBuffer+PACKET_HEADER_SIZE, NumBytes);
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;
  }
 return Retval;
 }

/* SETUP */
__declspec(dllexport) int HEIReadSetupData(HEIDevice *pDevice, WORD
SetupType, BYTE *pData, WORD *pSizeofData)
 {
 BYTE Buffer[100];
 BYTE RetBuffer[600];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;
 WORD *pWord;
 Buffer[DataOffset] = (BYTE) FUN_READ_SETUP_DATA;    /* This is the function
code! */
 Buffer[DataOffset+1] = 0;
 pWord = (WORD *) &Buffer[DataOffset+2];
 *pWord = SetupType;
 Total = DataOffset+4;
 NumBytes = sizeof(RetBuffer);
 pDevice->Timeout += EXTRA_TIME_FOR_SETUP_DATA;

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 pDevice->Timeout -= EXTRA_TIME_FOR_SETUP_DATA;
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  short int *pInt = (short int *) (RetBuffer+PACKET_HEADER_SIZE);
  NumBytes -= (PACKET_HEADER_SIZE+2);
  if ((WORD) NumBytes > *pSizeofData)
   {
   Retval = HEIE_BUFFER_TOO_SMALL;
   NumBytes = *pSizeofData;
   }
  if (*pInt)
   Retval = *pInt;
  (*pSizeofData) = NumBytes;
  memcpy(pData, RetBuffer+PACKET_HEADER_SIZE+2, NumBytes);
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;
  }
 return Retval;
 }
__declspec(dllexport) int HEIWriteSetupData(HEIDevice *pDevice, WORD
SetupType, BYTE *pData, WORD SizeofData)
 {
 BYTE Buffer[600];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD *pWord;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;
 Buffer[DataOffset] = (BYTE) FUN_WRITE_SETUP_DATA;    /* This is the
function code! */
 Buffer[DataOffset+1] = 0;
 pWord = (WORD *) &Buffer[DataOffset+2];
 *pWord = SetupType;
 Total = DataOffset+4+SizeofData;
 if (Total > sizeof(Buffer))
  {
#if 0
  BYTE Text[200];
  wsprintf(Text, "Total=%d  DataOffset=%d  SizeofData=%d  SizeofBuffer=%d",
   Total, DataOffset, SizeofData, sizeof(Buffer));
  MessageBox(NULL, Text, "HEIWriteSetupData", 0);
#endif
  return HEIE_DATA_TOO_LARGE;
  }
 memcpy(&Buffer[DataOffset+4], pData, SizeofData);
 NumBytes = sizeof(RetBuffer);

 pDevice->Timeout += EXTRA_TIME_FOR_SETUP_DATA;
 Error = SendPacketTwoResponses(pDevice, Buffer, Total, RetBuffer,
&NumBytes,
         TRUE, FALSE,
         0, NULL,
         30000, TRUE, TRUE);
 pDevice->Timeout -= EXTRA_TIME_FOR_SETUP_DATA;
#if 0
 pDevice->Timeout += EXTRA_TIME_FOR_SETUP_DATA;
 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 pDevice->Timeout -= EXTRA_TIME_FOR_SETUP_DATA;
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 NumBytes = sizeof(RetBuffer);
 Error = GetResponse(pDevice, RetBuffer, &NumBytes, 30000, TRUE, TRUE);
#endif
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  short int *pInt = (short int *) (RetBuffer+PACKET_HEADER_SIZE);
  if (*pInt)
   Retval = *pInt;
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;
  }
 return Retval;
 }
__declspec(dllexport) int HEIDeleteSetupData(HEIDevice *pDevice, WORD
SetupType)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD *pWord;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;
 Buffer[DataOffset] = (BYTE) FUN_DELETE_SETUP_DATA;    /* This is the
function code! */
 Buffer[DataOffset+1] = 0;
 pWord = (WORD *) &Buffer[DataOffset+2];
 *pWord = SetupType;
 Total = DataOffset+4;
 NumBytes = sizeof(RetBuffer);
 pDevice->Timeout += EXTRA_TIME_FOR_SETUP_DATA;
 Error = SendPacketTwoResponses(pDevice, Buffer, Total, RetBuffer,
&NumBytes,
         TRUE, FALSE,
         0, NULL,
         30000, TRUE, TRUE);
 pDevice->Timeout -= EXTRA_TIME_FOR_SETUP_DATA;


#if 0
 pDevice->Timeout += EXTRA_TIME_FOR_SETUP_DATA;
 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 pDevice->Timeout -= EXTRA_TIME_FOR_SETUP_DATA;
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 NumBytes = sizeof(RetBuffer);
 Error = GetResponse(pDevice, RetBuffer, &NumBytes, 30000, TRUE, TRUE);
#endif
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  short int *pInt = (short int *) (RetBuffer+PACKET_HEADER_SIZE);
  if (*pInt)
   Retval = *pInt;
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;
  }
 return Retval;
 }
__declspec(dllexport) int HEIEnumSetupData(HEIDevice *pDevice, WORD *pData,
WORD *pSizeofDataInWords)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[600];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;
 Buffer[DataOffset] = (BYTE) FUN_ENUM_SETUP_DATA;    /* This is the function
code! */
 Total = DataOffset+1;
 NumBytes = sizeof(RetBuffer);
 pDevice->Timeout += EXTRA_TIME_FOR_SETUP_DATA;

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 pDevice->Timeout -= EXTRA_TIME_FOR_SETUP_DATA;
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  /*int NumWords; */
  short int *pInt = (short int *) (RetBuffer+PACKET_HEADER_SIZE);
  short int *pNumWords = (short int *) (RetBuffer+PACKET_HEADER_SIZE+2);
  if ((WORD) *pNumWords > *pSizeofDataInWords)
   {
   Retval = HEIE_BUFFER_TOO_SMALL;
   *pNumWords = *pSizeofDataInWords;
   }
  if (*pInt)
   Retval = *pInt;
  (*pSizeofDataInWords) = *pNumWords;
  memcpy((char *) pData, (char *) (RetBuffer+PACKET_HEADER_SIZE+4),
*pNumWords * 2);
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;
  }
 return Retval;
 }

/* IO ACCESS */
__declspec(dllexport) int HEIReadIO(HEIDevice *pDevice, BYTE *pData, WORD
*DataSize)
 {
 BYTE Buffer[100];
 BYTE RetBuffer[1200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;

 Buffer[DataOffset] = FUN_READ_IO; /* This is the function code! */
 Total = DataOffset+1;
 if (pData && *pData == 0xB1)
  {
  Buffer[DataOffset+1] = *pData;
  Total++;
  }
 NumBytes = sizeof(RetBuffer);
 //NumBytes = *DataSize;
 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes,
(pDevice->ParallelPackets) ? FALSE : TRUE, TRUE);
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  short int *pInt = (short int *) &RetBuffer[PACKET_HEADER_SIZE];
  NumBytes -= PACKET_HEADER_SIZE;
  NumBytes -= 2;
  if ((WORD) NumBytes > *DataSize)
   {
   Retval = HEIE_BUFFER_TOO_SMALL;
   NumBytes = *DataSize;
   }
  if (*pInt)
   Retval = (*pInt) | 0x8000;
  memcpy(pData, RetBuffer+PACKET_HEADER_SIZE+2, NumBytes);
  (*DataSize) = NumBytes;
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;
  (*DataSize) = 0;
  }
 return Retval;
 }

__declspec(dllexport) int HEIWriteIO(HEIDevice *pDevice, BYTE *pData, WORD
SizeofData, BYTE *pReturnData, WORD *pSizeofReturnData)
 {
 BYTE Buffer[1200];
 BYTE RetBuffer[1200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;
 Buffer[DataOffset] = FUN_WRITE_IO;    /* This is the function code! */

 Total = DataOffset+1+SizeofData;
 if (Total > sizeof(Buffer))
  return HEIE_DATA_TOO_LARGE;
 memcpy(Buffer+DataOffset+1, pData, SizeofData);
 NumBytes = sizeof(RetBuffer);
 //NumBytes = *pSizeofReturnData;

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes,
(pDevice->ParallelPackets) ? FALSE : TRUE, TRUE);
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  short int *pInt = (short int *) &RetBuffer[PACKET_HEADER_SIZE];
  if (pReturnData && pSizeofReturnData)
   {
   NumBytes -= PACKET_HEADER_SIZE;
   NumBytes -= 2;
   if ((WORD) NumBytes > *pSizeofReturnData)
    {
    Retval = HEIE_BUFFER_TOO_SMALL;
    NumBytes = *pSizeofReturnData;
    }
   memcpy(pReturnData, RetBuffer+PACKET_HEADER_SIZE+2, NumBytes);
   (*pSizeofReturnData) = NumBytes;
   }
  if (*pInt)
   Retval = (*pInt) | 0x8000;
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;
  if (pSizeofReturnData)
   (*pSizeofReturnData) = 0;
  }
 return Retval;
 }

__declspec(dllexport) int HEIWriteIONoRead(HEIDevice *pDevice, BYTE *pData,
WORD SizeofData)
 {
 BYTE Buffer[1200];
 BYTE RetBuffer[1200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;
 Buffer[DataOffset] = FUN_WRITE_IO_NO_READ;    /* This is the function code!
*/

 Total = DataOffset+1+SizeofData;
 if (Total > sizeof(Buffer))
  return HEIE_DATA_TOO_LARGE;
 memcpy(Buffer+DataOffset+1, pData, SizeofData);
 NumBytes = sizeof(RetBuffer);
 //NumBytes = *pSizeofReturnData;

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes,
(pDevice->ParallelPackets) ? FALSE : TRUE, TRUE);
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  short int *pInt = (short int *) &RetBuffer[PACKET_HEADER_SIZE];
  if (*pInt)
   Retval = (*pInt) | 0x8000;
  }
 else
  Retval = HEIE_ZERO_BYTES_RECEIVED;
 return Retval;
 }

__declspec(dllexport) int HEIPetDevice(HEIDevice *pDevice)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int NumBytes;
 Buffer[DataOffset] = FUN_PET_LINK;
 Buffer[DataOffset+1] = 0;
 Total = DataOffset+2;
 NumBytes = sizeof(RetBuffer);
 return _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 }
__declspec(dllexport) int HEIReadEthernetStats(HEIDevice *pDevice, BYTE
*pData, WORD *DataSize, BOOL Clear)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;
 Buffer[DataOffset] = FUN_READ_ETHERNET_STATS;   /* This is the function
code! */
 Buffer[DataOffset+1] = 0;
 Buffer[DataOffset+2] = Clear ? 1 : 0;
 Total = DataOffset+3;
 NumBytes = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  NumBytes -= PACKET_HEADER_SIZE;
  if ((WORD) NumBytes > *DataSize)
   {
   Retval = HEIE_BUFFER_TOO_SMALL;
   NumBytes = *DataSize;
   }
  memcpy(pData, RetBuffer+PACKET_HEADER_SIZE, NumBytes);
  (*DataSize) = NumBytes;
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;
  (*DataSize) = 0;
  }
 return Retval;
 }

__declspec(dllexport) int HEIReadModuleStatus(HEIDevice *pDevice, BYTE
*pData, WORD *DataSize, BOOL Reset)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[600];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;
 Buffer[DataOffset] = FUN_READ_MODULE_STATUS;   /* This is the function
code! */
 if (pData && *pData == 0xB1)
  Buffer[DataOffset+1] = 1;
 else
  Buffer[DataOffset+1] = 0;
 Buffer[DataOffset+2] = Reset ? 1 : 0;
 Total = DataOffset+3;
 NumBytes = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  short int *pInt = (short int *) &RetBuffer[PACKET_HEADER_SIZE];
  NumBytes -= PACKET_HEADER_SIZE;
  NumBytes -= 2;
  if ((WORD) NumBytes > *DataSize)
   {
   Retval = HEIE_BUFFER_TOO_SMALL;
   NumBytes = *DataSize;
   }
  if (*pInt)
   Retval = *pInt;
  memcpy(pData, RetBuffer+PACKET_HEADER_SIZE+2, NumBytes);
  (*DataSize) = NumBytes;
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;
  (*DataSize) = 0;
  }
 return Retval;
 }


/* CCM STUFF */
#define CCM_READ   0x1E
#define CCM_WRITE   0x20

__declspec(dllexport) int HEICCMRequest(HEIDevice *pDevice, BOOL bWrite,
BYTE DataType, WORD Address, WORD DataLen, BYTE *pData)
 {
 BYTE Buffer[320];
 BYTE RetBuffer[320];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int NumBytes;
 BYTE *pRet;
 short int *pError;
 BYTE VerifyData[2];

#if DEBUG_FILE
 DebugString("In HEICCMRequest %u", AppVal);
#endif
 if(DataLen > 256)
  return HEIE_INVALID_REQUEST;

   /* Function */
 Buffer[DataOffset] = FUN_CCM_REQUEST;

 /* Unused */
 Buffer[DataOffset+1] = 0;
 /* Request Code. */
 Buffer[DataOffset+2] = 0x01;

 /* Direction */
 Buffer[DataOffset+3] = bWrite ? CCM_WRITE : CCM_READ;

 /* Length */
 Buffer[DataOffset+4] = (DataLen == 256) ? 0 : (BYTE)DataLen;

 /* LSB of Address */
 Buffer[DataOffset+5] = (BYTE) (Address & 0xFF);

 /* MSB of Address */
 Buffer[DataOffset+6] = (BYTE) ((Address>>8) & 0xFF);

 /* Data Type */
 Buffer[DataOffset+7] = DataType;
 Total = DataOffset+8;
 if (bWrite)
  {
  /* We are writing. */
  memcpy(&Buffer[DataOffset+8], pData, DataLen);
  Total += DataLen;
  }
 NumBytes = sizeof(RetBuffer);

 VerifyData[0] = FUN_ACK;
 VerifyData[1] = FUN_CCM_REQUEST;
 Error = SendPacketTwoResponses(pDevice, Buffer, Total, RetBuffer,
&NumBytes,
         (pDevice->ParallelPackets) ? FALSE : TRUE, TRUE,
         2, VerifyData,
         0, TRUE, TRUE);
 if (Error == HEIE_INVALID_RESPONSE)
  {
  short int *pError = (short int *) (RetBuffer+PACKET_HEADER_SIZE+2);
#if DEBUG_FILE
  DebugString("Error %d (0x%X) from HEICCMRequest %u", *pError, *pError,
AppVal);
#endif
  return *pError;
  }

#if 0
 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes,
(pDevice->ParallelPackets) ? FALSE : TRUE, TRUE);
 if (Error && !(Error & HEIW_FIRST_WARNING))
  {
#if DEBUG_FILE
  DebugString("Error %d (0x%X) from HEICCMRequest %u", Error, Error,
AppVal);
#endif
  return Error;
  }
 /* Check and make sure we got an ack. */
 pRet = (RetBuffer+PACKET_HEADER_SIZE);

 if (*pRet != FUN_ACK || (*(pRet+1) != FUN_CCM_REQUEST))
  {
  short int *pError = (short int *) (RetBuffer+PACKET_HEADER_SIZE+2);
#if DEBUG_FILE
  DebugString("Error %d (0x%X) from HEICCMRequest %u", *pError, *pError,
AppVal);
#endif
  return *pError;
  }
 NumBytes = sizeof(RetBuffer);
 Error = GetResponse(pDevice, RetBuffer, &NumBytes, 0, TRUE, TRUE);
#endif

 if (Error && !(Error & HEIW_FIRST_WARNING))
  {
#if DEBUG_FILE
  DebugString("Error %d (0x%X) from HEICCMRequest %u", Error, Error,
AppVal);
#endif
  return Error;
  }
 NumBytes -= PACKET_HEADER_SIZE;
 pRet = (RetBuffer + PACKET_HEADER_SIZE);
 if (*pRet != FUN_RESPONSE || *(pRet+1) != FUN_CCM_REQUEST)
  {
#if DEBUG_FILE
  Error = HEIE_INVALID_RESPONSE;
  DebugString("Error %d (0x%X) from HEICCMRequest %u", Error, Error,
AppVal);
#endif
  return HEIE_INVALID_RESPONSE;
  }

 pError = (short int *) (RetBuffer+PACKET_HEADER_SIZE+2);

 if (*pError)
  {
#if DEBUG_FILE
  DebugString("Error %d (0x%X) from HEICCMRequest %u", *pError, *pError,
AppVal);
#endif
  return *pError;
  }

 NumBytes -= 4;
 if(!bWrite && NumBytes != (int)DataLen)
  {
#if DEBUG_FILE
  Error = HEIE_INVALID_REQUEST;
  DebugString("Error %d (0x%X) from HEICCMRequest %u", Error, Error,
AppVal);
#endif
  return HEIE_INVALID_REQUEST;
  }

 memcpy(pData, RetBuffer+PACKET_HEADER_SIZE+4, DataLen);
#if DEBUG_FILE
 DebugString("Leaving HEICCMRequest %u", AppVal);
#endif

 return HEIE_NULL;
 }

__declspec(dllexport) int HEIKSEQRequest(HEIDevice *pDevice, WORD DataLenIn,
BYTE *pData, WORD *pDataLen)
 {
 BYTE Buffer[320];
 BYTE RetBuffer[320];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int NumBytes;
 BYTE *pRet;
 short int *pError;
 int Retval;
 BYTE VerifyData[2];
#if DEBUG_FILE
 DebugString("In HEIKSEQRequest %u", AppVal);
#endif
 if(DataLenIn > 256)
  return HEIE_INVALID_REQUEST;
 /* Function */
 Buffer[DataOffset] = FUN_KSEQ_REQUEST;

 /* Unused */
 Buffer[DataOffset+1] = 0;
 /* Request Code. */
 Buffer[DataOffset+2] = (DataLenIn == 256) ? 0 : (BYTE)DataLenIn;

 /* Unused */
 Buffer[DataOffset+3] = 0;

 /* Copy task code data. */
 memcpy(&Buffer[DataOffset+4], pData, DataLenIn);
 Total = DataOffset+4+DataLenIn;
 NumBytes = sizeof(RetBuffer);

 VerifyData[0] = FUN_ACK;
 VerifyData[1] = FUN_KSEQ_REQUEST;
 Error = SendPacketTwoResponses(pDevice, Buffer, Total, RetBuffer,
&NumBytes,
         (pDevice->ParallelPackets) ? FALSE : TRUE, TRUE,
         2, VerifyData,
         0, TRUE, TRUE);
 if (Error == HEIE_INVALID_RESPONSE)
  {
  short int *pError = (short int *) (RetBuffer+PACKET_HEADER_SIZE+2);
  return *pError;
  }
#if 0
 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes,
(pDevice->ParallelPackets) ? FALSE : TRUE, TRUE);
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 /* Check and make sure we got an ack. */
 pRet = (RetBuffer+PACKET_HEADER_SIZE);

 if (*pRet != FUN_ACK || (*(pRet+1) != FUN_KSEQ_REQUEST))
  {
  short int *pError = (short int *) (RetBuffer+PACKET_HEADER_SIZE+2);
  return *pError;
  }
 NumBytes = sizeof(RetBuffer);
 Error = GetResponse(pDevice, RetBuffer, &NumBytes, 0, TRUE, TRUE);
#endif
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;

 NumBytes -= PACKET_HEADER_SIZE;
 pRet = (RetBuffer + PACKET_HEADER_SIZE);
 if (*pRet != FUN_RESPONSE || *(pRet+1) != FUN_KSEQ_REQUEST)
  {
  return HEIE_INVALID_RESPONSE;
  }

 pError = (short int *) (RetBuffer+PACKET_HEADER_SIZE+2);

 if (*pError)
  return *pError;

 NumBytes -= 4;

  Retval = HEIE_NULL;
 if ((WORD) NumBytes > *pDataLen)
  {
  Retval = HEIE_BUFFER_TOO_SMALL;
  NumBytes = *pDataLen;
  }

 memcpy(pData, RetBuffer+PACKET_HEADER_SIZE+4, NumBytes);
 *pDataLen = NumBytes;

#if DEBUG_FILE
 DebugString("Leaving HEIKSEQRequest", Retval);
#endif

 return Retval;
 }
// Returns number of bytes not written.
__declspec(dllexport) int HEIWriteComm(HEIDevice *pDevice, WORD Num2Write,
BYTE *pData)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 WORD *pWord;
 int Error;
 int NumBytes;
 Buffer[DataOffset] = FUN_SERIAL_PORT;
 Buffer[DataOffset+1] = SPF_WRITE_COMM;
 pWord = (WORD *) &Buffer[DataOffset+2];
 *pWord = Num2Write;
 if (Num2Write > (sizeof(Buffer) - DataOffset - 4))
  return HEIE_DATA_TOO_LARGE;
 memcpy(Buffer+DataOffset+4, pData, Num2Write);
 Total = DataOffset+4+Num2Write;
 NumBytes = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 //if (Error) return Error;
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 if (NumBytes)
  return *((short int *) (RetBuffer+PACKET_HEADER_SIZE));
 else
  return HEIE_ZERO_BYTES_RECEIVED;
 }
__declspec(dllexport) int HEIReadComm(HEIDevice *pDevice, WORD *pNum2Read,
BYTE *pData)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 WORD *pWord;
 int Error;
 int Retval;
 int NumBytes;
 Buffer[DataOffset] = FUN_SERIAL_PORT;
 Buffer[DataOffset+1] = SPF_READ_COMM;
 pWord = (WORD *) &Buffer[DataOffset+2];
 *pWord = *pNum2Read;
 Total = DataOffset+4;
 NumBytes = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 //if (Error) return Error;
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  short int *pInt = (short int *) (RetBuffer+PACKET_HEADER_SIZE);
  short int *pNumReturned = (short int *) (RetBuffer+PACKET_HEADER_SIZE+2);
  if (*pInt)
   Retval = *pInt;
  (*pNum2Read) = *pNumReturned;
  memcpy(pData, RetBuffer+PACKET_HEADER_SIZE+4, *pNumReturned);
  }
 else
  Retval = HEIE_ZERO_BYTES_RECEIVED;
 return Retval;
 }
__declspec(dllexport) int HEIGetRXAvailable(HEIDevice *pDevice, WORD
*pAvailable)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int NumBytes;
 Buffer[DataOffset] = FUN_SERIAL_PORT;
 Buffer[DataOffset+1] = SPF_RX_AVAILABLE;
 Total = DataOffset+2;
 NumBytes = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 //if (Error) return Error;
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 if (NumBytes)
  {
  *pAvailable = *((WORD *) (RetBuffer+PACKET_HEADER_SIZE+2));
  return *((short int *) (RetBuffer+PACKET_HEADER_SIZE));
  }
 else
  return HEIE_ZERO_BYTES_RECEIVED;
 }
__declspec(dllexport) int HEIFlushRXQueue(HEIDevice *pDevice)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int NumBytes;
 Buffer[DataOffset] = FUN_SERIAL_PORT;
 Buffer[DataOffset+1] = SPF_RX_FLUSH;
 Total = DataOffset+2;
 NumBytes = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 //if (Error) return Error;
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 if (NumBytes)
  return *((short int *) (RetBuffer+PACKET_HEADER_SIZE));
 else
  return HEIE_ZERO_BYTES_RECEIVED;
 }

__declspec(dllexport) int HEISetupSerialPort(HEIDevice *pDevice, SerialSetup
*pSetup, BOOL WriteToFlash)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int NumBytes;
 Buffer[DataOffset] = FUN_SERIAL_PORT;
 Buffer[DataOffset+1] = SPF_SETUP;
 Buffer[DataOffset+2] = (BYTE) WriteToFlash;
 Buffer[DataOffset+3] = 0;
 memcpy(Buffer+DataOffset+4, pSetup, sizeof(SerialSetup));
 Total = DataOffset+4+sizeof(SerialSetup);
 NumBytes = sizeof(RetBuffer);
 if (WriteToFlash)
  {
  pDevice->Timeout += EXTRA_TIME_FOR_SETUP_DATA;
  Error = SendPacketTwoResponses(pDevice, Buffer, Total, RetBuffer,
&NumBytes,
          TRUE, FALSE,
          0, NULL,
          30000, TRUE, TRUE);
  pDevice->Timeout -= EXTRA_TIME_FOR_SETUP_DATA;
  }
 else
  {
  Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
  }
 //if (Error)
 // return Error;
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
#if 0
 if (WriteToFlash)
  pDevice->Timeout += EXTRA_TIME_FOR_SETUP_DATA;

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 if (WriteToFlash)
  pDevice->Timeout -= EXTRA_TIME_FOR_SETUP_DATA;
 if (Error) return Error;
 if (WriteToFlash)
  {
  NumBytes = sizeof(RetBuffer);
  Error = GetResponse(pDevice, RetBuffer, &NumBytes, 30000, TRUE, TRUE);
  }
#endif
 if (NumBytes)
  return *((short int *) (RetBuffer+PACKET_HEADER_SIZE));
 else
  return HEIE_ZERO_BYTES_RECEIVED;
 }

__declspec(dllexport) int HEIReadSerialPortSetup(HEIDevice *pDevice,
SerialSetup *pSetup)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int NumBytes;
 Buffer[DataOffset] = FUN_SERIAL_PORT;
 Buffer[DataOffset+1] = SPF_READ_SETUP;
 Buffer[DataOffset+2] = 0;
 Buffer[DataOffset+3] = 0;
 Total = DataOffset+4;
 NumBytes = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 //if (Error) return Error;
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 if (NumBytes)
  {
  // Copy data into user buffer.
  memcpy(pSetup, RetBuffer+PACKET_HEADER_SIZE, sizeof(SerialSetup));
  return 0;
  }
 else
  return HEIE_ZERO_BYTES_RECEIVED;
 }

__declspec(dllexport) int HEIGetTXLeft(HEIDevice *pDevice, WORD *pLeft)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 //int Retval;
 int NumBytes;
 Buffer[DataOffset] = FUN_SERIAL_PORT;
 Buffer[DataOffset+1] = SPF_TX_LEFT;
 Total = DataOffset+2;
 NumBytes = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 //if (Error) return Error;
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 //Retval = Error;
 if (NumBytes)
  {
  *pLeft = *((WORD *) (RetBuffer+PACKET_HEADER_SIZE+2));
  return *((short int *) (RetBuffer+PACKET_HEADER_SIZE));
  }
 else
  return HEIE_ZERO_BYTES_RECEIVED;
 }
/* PLC MEMORY STUFF */
__declspec(dllexport) int HEIReadMemory(HEIDevice *pDevice, WORD Type, DWORD
Offset, WORD NumBytes, BYTE *pBuffer)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[600];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Num;
 WORD *pWord;
 DWORD *pDWord;
 Buffer[DataOffset] = FUN_READ_MEMORY;
 Buffer[DataOffset+1] = 0;

 pWord = (WORD *) &Buffer[DataOffset+2];
 *pWord++ = Type;
 *pWord++ = NumBytes;
 pDWord = (DWORD *) &Buffer[DataOffset+6];
 *pDWord++ = Offset;
 Total = DataOffset+10;
 Num = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &Num, TRUE, FALSE);
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 //if (Error)
 // return Error;
 if (Num)
  {
  short int *pError = (short int *) (RetBuffer+PACKET_HEADER_SIZE);

  if (!((*pError) & 0x0FFF) || (*pError == HEIE_LENGTH_WARNING))
   {
   // Copy the memory.
   memcpy(pBuffer, RetBuffer+PACKET_HEADER_SIZE+2, NumBytes);
   }

  return *pError;
  }
 else
  return HEIE_ZERO_BYTES_RECEIVED;

/* return 0; */
 }

__declspec(dllexport) int HEIWriteMemory(HEIDevice *pDevice, WORD Type,
DWORD Offset, WORD NumBytes, BYTE *pBuffer)
 {
 BYTE Buffer[600];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Num;
 WORD *pWord;
 DWORD *pDWord;
 if (NumBytes > 512)
  return HEIE_DATA_TOO_LARGE;
 Buffer[DataOffset] = FUN_WRITE_MEMORY;
 Buffer[DataOffset+1] = 0;

 pWord = (WORD *) &Buffer[DataOffset+2];
 *pWord++ = Type;
 *pWord++ = NumBytes;
 pDWord = (DWORD *) &Buffer[DataOffset+6];
 *pDWord++ = Offset;

 memcpy(Buffer+DataOffset+10, pBuffer, NumBytes);
 Total = DataOffset+10+NumBytes;
 Num = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &Num, TRUE, FALSE);
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 //if (Error) return Error;
 if (Num)
  return *((short int *) (RetBuffer+PACKET_HEADER_SIZE));
 else
  return HEIE_ZERO_BYTES_RECEIVED;

 /* return 0; */
 }

__declspec(dllexport) int HEIAccessMemory(HEIDevice *pDevice, MemRef
MemRefs[], WORD NumRefs)
 {
 WORD DataOffset = pDevice->DataOffset;
 BYTE Buffer[600];
 BYTE RetBuffer[600];
 BYTE *pSendData;
 WORD x;
 WORD *pWord;
 WORD ReadSize = 2 + 2;     // Returned error value is 2 bytes long
           // Returned num MemRefs is 2 bytes long
 WORD TotalSize = 4 + DataOffset;  // Header info is 4 bytes long
 int Num;
 int Error;
 Buffer[DataOffset] = FUN_ACCESS_MEMORY;
 Buffer[DataOffset+1] = 0;
 pWord = (WORD *) &Buffer[DataOffset+2];
 *pWord = NumRefs;
 pSendData = &Buffer[DataOffset+4];
 for (x=0; x<NumRefs; x++)
  {
  memcpy(pSendData, &MemRefs[x], sizeof(MemRefDetail));
  TotalSize += sizeof(MemRefDetail);
  pSendData += sizeof(MemRefDetail);
  if (MemRefs[x].Detail.Direction == ACCESS_READ)
   {
   // Read request.
   ReadSize += (MemRefs[x].Detail.NumBytes + sizeof(MemRefDetail));
   }
  else if (MemRefs[x].Detail.Direction == ACCESS_WRITE)
   {
   // Write request.
   memcpy(pSendData, MemRefs[x].pBuffer, MemRefs[x].Detail.NumBytes);
   TotalSize += MemRefs[x].Detail.NumBytes;
   pSendData += MemRefs[x].Detail.NumBytes;
   }
  else
   {
   return HEIE_INVALID_REQUEST;
   }
  if ((TotalSize > sizeof(Buffer)) || (ReadSize > sizeof(RetBuffer)))
   {
   return HEIE_DATA_TOO_LARGE;
   }
  }
 // Ready to send.
 Num = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, TotalSize, RetBuffer, &Num, TRUE,
FALSE);
 //if (Error) return Error;
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 if (Num)
  {
  short int *pError = (short int *) (RetBuffer+PACKET_HEADER_SIZE);
  short int *pNum = (short int *) (RetBuffer+PACKET_HEADER_SIZE+2);

  //if (!*pError && *pNum)
  if (!((*pError) & 0x0FFF) && *pNum)
   {
   // No errors, and we have some read requests returned.
   WORD x;
   MemRefDetail *pReturnDetail = (MemRefDetail *)
(RetBuffer+PACKET_HEADER_SIZE+4);
   for (x=0; x<NumRefs; x++)
    {
    // Find a read request.
    if (MemRefs[x].Detail.Direction == ACCESS_READ)
     {
     // Read request; Make sure it matches.
     if (MemRefs[x].Detail.Type  == pReturnDetail->Type &&
      MemRefs[x].Detail.Offset == pReturnDetail->Offset &&
      MemRefs[x].Detail.NumBytes == pReturnDetail->NumBytes)
      {
      // Requests match, so copy data.
      BYTE *pData = (BYTE *) pReturnDetail;
      pData += sizeof(MemRefDetail);
      memcpy(MemRefs[x].pBuffer, pData, MemRefs[x].Detail.NumBytes);
      // Reset for next one.
      pData += MemRefs[x].Detail.NumBytes;
      pReturnDetail = (MemRefDetail *) pData;
      }
     else
      {
      // Requests don't match, so return error.
      return HEIE_INVALID_RESPONSE;
      }
     }
    }
   }

  return *pError;
  }
 else
  return HEIE_ZERO_BYTES_RECEIVED;
 }

__declspec(dllexport) int HEIENumMemory(HEIDevice *pDevice, WORD
*pSizeofDataInTypes, MemoryTypeDef *pData)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[600];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;
 Buffer[DataOffset] = (BYTE) FUN_ENUM_MEMORY;    /* This is the function
code! */
 Total = DataOffset+1;
 NumBytes = sizeof(RetBuffer);
 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 /* Check for error and not warning. */
 //if (Error)
 // return Error;
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  /*int NumTypes; */
  short int *pInt = (short int *) (RetBuffer+PACKET_HEADER_SIZE);
  short int *pNumTypes = (short int *) (RetBuffer+PACKET_HEADER_SIZE+2);
  if ((WORD) *pNumTypes > *pSizeofDataInTypes)
   {
   Retval = HEIE_BUFFER_TOO_SMALL;
   *pNumTypes = *pSizeofDataInTypes;
   }
  if (*pInt)
   Retval = *pInt;
  (*pSizeofDataInTypes) = *pNumTypes;
  memcpy((char *) pData, (char *) (RetBuffer+PACKET_HEADER_SIZE+4),
(*pNumTypes) * sizeof(MemoryTypeDef));
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;
  }
 return Retval;
 }
//BYTE SharedRamArea = 0;
__declspec(dllexport) int HEIReadSharedRAM(HEIDevice *pDevice, WORD Base,
WORD Slot, WORD Address, WORD Bytes2Read, BYTE *pBuffer)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[600];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Num;
 WORD *pWord;
 BYTE SharedRamArea = 0;
 Buffer[DataOffset] = FUN_READ_SHARED_RAM;
 if (Address & 0x8000)
  {
  SharedRamArea = 1;
  Address &= 0x7FFF;
  }
 Buffer[DataOffset+1] = SharedRamArea;

 pWord = (WORD *) &Buffer[DataOffset+2];
 *pWord++ = Base;
 *pWord++ = Slot;
 *pWord++ = Address;
 *pWord++ = Bytes2Read;
 Total = DataOffset+10;
 Num = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &Num, TRUE, FALSE);
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 //if (Error)
 // return Error;
 if (Num)
  {
  short int *pError = (short int *) (RetBuffer+PACKET_HEADER_SIZE);

  //if (!*pError || (*pError == LENGTH_WARNING))
  if (!((*pError) & 0x0FFF) || (*pError == HEIE_LENGTH_WARNING))
   {
   // Copy the memory.
   memcpy(pBuffer, RetBuffer+PACKET_HEADER_SIZE+2, Bytes2Read);
   }

  return *pError;
  }
 else
  return HEIE_ZERO_BYTES_RECEIVED;

 /* return 0; */
 }

__declspec(dllexport) int HEIWriteSharedRAM(HEIDevice *pDevice, WORD Base,
WORD Slot, WORD Address, WORD Bytes2Write, BYTE *pBuffer)
 {
 BYTE Buffer[600];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Num;
 WORD *pWord;
 BYTE SharedRamArea = 0;
 if (Bytes2Write > 256)
  return HEIE_DATA_TOO_LARGE;
 Buffer[DataOffset] = FUN_WRITE_SHARED_RAM;
 if (Address & 0x8000)
  {
  SharedRamArea = 1;
  Address &= 0x7FFF;
  }
 Buffer[DataOffset+1] = SharedRamArea;

 pWord = (WORD *) &Buffer[DataOffset+2];
 *pWord++ = Base;
 *pWord++ = Slot;
 *pWord++ = Address;
 *pWord++ = Bytes2Write;

 memcpy(Buffer+DataOffset+10, pBuffer, Bytes2Write);
 Total = DataOffset+10+Bytes2Write;
 Num = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &Num, TRUE, FALSE);
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 //if (Error) return Error;
 if (Num)
  return *((short int *) (RetBuffer+PACKET_HEADER_SIZE));
 else
  return HEIE_ZERO_BYTES_RECEIVED;

 /* return 0; */
 }

/*
** Calculate, 16 Bit CRC
*/
/* number of bits in CRC: don't change it.  */
#define W 16
/* this the number of bits per char: don't change it. */
#define B 8
static unsigned short crctab[1<<B] = {
    0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
    0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
    0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
    0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
    0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
    0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
    0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
    0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
    0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
    0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
    0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
    0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
    0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
    0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
    0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
    0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
    0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
    0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
    0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
    0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
    0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
    0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
    0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
    0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
    0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
    0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
    0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
    0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
    0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
    0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
    0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
    0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
    };
WORD CalcCRC(WORD    icrc,
            BYTE   *icp,
            WORD    icnt)
 {
 register WORD crc = icrc;
 register BYTE *cp = icp;
 register WORD cnt = icnt;
 while( cnt-- )
  crc = (crc<<B) ^ crctab[(crc>>(W-B)) ^ *cp++];
 return( crc );
 }

/*
**
** WinPLC Specific Functions
**
*/
__declspec(dllexport) int WPLCSetOSLoad(HEIDevice *pDevice, int Val)
 {
 BYTE Buffer[100];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int NumBytes;
 Buffer[DataOffset] = FUN_SET_OS_LOAD;
 Buffer[DataOffset+1] = ~FUN_SET_OS_LOAD;
 memcpy(&Buffer[DataOffset+2], &Val, sizeof(int));
 Total = DataOffset+2+sizeof(int);
 NumBytes = sizeof(RetBuffer);
 return _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 }

__declspec(dllexport) int WPLCReboot(HEIDevice *pDevice)
 {
 BYTE Buffer[100];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int NumBytes;
 Buffer[DataOffset] = FUN_REBOOT;
 Buffer[DataOffset+1] = ~FUN_REBOOT;
 Total = DataOffset+2;
 NumBytes = sizeof(RetBuffer);
 return _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 }
__declspec(dllexport) int HEIReboot(HEIDevice *pDevice)
 {
 BYTE Buffer[100];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int NumBytes;
 Buffer[DataOffset] = FUN_REBOOT;
 Buffer[DataOffset+1] = ~FUN_REBOOT;
 Total = DataOffset+2;
 NumBytes = sizeof(RetBuffer);
 return _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 }

__declspec(dllexport) int WPLCRunProgram(HEIDevice *pDevice, BYTE *pProgram)
 {
 BYTE Buffer[500];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 BYTE *pArgs, *pData;
 WORD Total;
 int NumBytes;
 short int *pError;
 memset(Buffer, 0, sizeof(Buffer));
 Buffer[DataOffset] = FUN_RUN_PROGRAM;
 Buffer[DataOffset+1] = ~FUN_RUN_PROGRAM;
 pArgs = pProgram;
 if (!*pArgs)
  return -1;
 // Skip whitespace at front.
 while (*pArgs == ' ')
  pArgs++;
 pData = &Buffer[DataOffset+2];
 // Copy program name.
 while (*pArgs && (*pArgs != ' '))
  {
  *pData++ = *pArgs++;
  }
 while (isspace(*pArgs))
  pArgs++;
 strcpy((char *) &Buffer[DataOffset+66], (char *) pArgs);
 Total = DataOffset+2+64+strlen((char *) pArgs)+1;
 NumBytes = sizeof(RetBuffer);
 _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE, FALSE);
 pError = (short int *) (RetBuffer+PACKET_HEADER_SIZE);
 return *pError;
 }

/*
**
** THIS IS THE MODIFIED SERIAL PORT FUNCTIONS THAT ACCEPT A BYTE FOR THE
PORT NUMBER
**
*/
__declspec(dllexport) int HEIWriteCommEx(HEIDevice *pDevice, BYTE Port, WORD
Num2Write, BYTE *pData)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 WORD *pWord;
 int Error;
 int NumBytes;
 //Port = (Port - 1) << 4;
 Buffer[DataOffset] = FUN_SERIAL_PORT;
 Buffer[DataOffset+1] = SPF_WRITE_COMM + 0x80; //Port;
 Buffer[DataOffset+2] = Port-1;
 pWord = (WORD *) &Buffer[DataOffset+3];
 *pWord = Num2Write;
 if (Num2Write > (sizeof(Buffer) - DataOffset - 5))
  return HEIE_DATA_TOO_LARGE;
 memcpy(Buffer+DataOffset+5, pData, Num2Write);
 Total = DataOffset+5+Num2Write;
 NumBytes = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 //if (Error) return Error;
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 if (NumBytes)
  return *((short int *) (RetBuffer+PACKET_HEADER_SIZE));
 else
  return HEIE_ZERO_BYTES_RECEIVED;
 }
__declspec(dllexport) int HEIReadCommEx(HEIDevice *pDevice, BYTE Port, WORD
*pNum2Read, BYTE *pData)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 WORD *pWord;
 int Error;
 int Retval;
 int NumBytes;
 //Port = (Port - 1) << 4;
 Buffer[DataOffset] = FUN_SERIAL_PORT;
 Buffer[DataOffset+1] = SPF_READ_COMM + 0x80; //Port;
 Buffer[DataOffset+2] = Port-1;
 pWord = (WORD *) &Buffer[DataOffset+3];
 *pWord = *pNum2Read;
 Total = DataOffset+5;
 NumBytes = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 //if (Error) return Error;
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  short int *pInt = (short int *) (RetBuffer+PACKET_HEADER_SIZE);
  short int *pNumReturned = (short int *) (RetBuffer+PACKET_HEADER_SIZE+2);
  if (*pInt)
   Retval = *pInt;
  (*pNum2Read) = *pNumReturned;
  memcpy(pData, RetBuffer+PACKET_HEADER_SIZE+4, *pNumReturned);
  }
 else
  Retval = HEIE_ZERO_BYTES_RECEIVED;
 return Retval;
 }
__declspec(dllexport) int HEIGetRXAvailableEx(HEIDevice *pDevice, BYTE Port,
WORD *pAvailable)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int NumBytes;
 //Port = (Port - 1) << 4;
 Buffer[DataOffset] = FUN_SERIAL_PORT;
 Buffer[DataOffset+1] = SPF_RX_AVAILABLE + 0x80; //Port;
 Buffer[DataOffset+2] = Port-1;
 Total = DataOffset+3;
 NumBytes = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 //if (Error) return Error;
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 if (NumBytes)
  {
  *pAvailable = *((WORD *) (RetBuffer+PACKET_HEADER_SIZE+2));
  return *((short int *) (RetBuffer+PACKET_HEADER_SIZE));
  }
 else
  return HEIE_ZERO_BYTES_RECEIVED;
 }
__declspec(dllexport) int HEIFlushRXQueueEx(HEIDevice *pDevice, BYTE Port)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int NumBytes;
 //Port = (Port - 1) << 4;
 Buffer[DataOffset] = FUN_SERIAL_PORT;
 Buffer[DataOffset+1] = SPF_RX_FLUSH + 0x80; //Port;
 Buffer[DataOffset+2] = Port-1;
 Total = DataOffset+3;
 NumBytes = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 //if (Error) return Error;
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 if (NumBytes)
  return *((short int *) (RetBuffer+PACKET_HEADER_SIZE));
 else
  return HEIE_ZERO_BYTES_RECEIVED;
 }
__declspec(dllexport) int HEIFlushTXQueueEx(HEIDevice *pDevice, BYTE Port)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int NumBytes;
 //Port = (Port - 1) << 4;
 Buffer[DataOffset] = FUN_SERIAL_PORT;
 Buffer[DataOffset+1] = SPF_TX_FLUSH + 0x80; //Port;
 Buffer[DataOffset+2] = Port-1;
 Total = DataOffset+3;
 NumBytes = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 //if (Error) return Error;
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 if (NumBytes)
  return *((short int *) (RetBuffer+PACKET_HEADER_SIZE));
 else
  return HEIE_ZERO_BYTES_RECEIVED;
 }
__declspec(dllexport) int HEISetupSerialPortEx(HEIDevice *pDevice, BYTE
Port, SerialSetup *pSetup, BOOL WriteToFlash)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int NumBytes;
 //Port = (Port - 1) << 4;
 Buffer[DataOffset] = FUN_SERIAL_PORT;
 Buffer[DataOffset+1] = SPF_SETUP + 0x80; //Port;
 Buffer[DataOffset+2] = Port-1;
 Buffer[DataOffset+3] = (BYTE) WriteToFlash;
 Buffer[DataOffset+4] = 0;
 memcpy(Buffer+DataOffset+5, pSetup, sizeof(SerialSetup));
 Total = DataOffset+5+sizeof(SerialSetup);
 NumBytes = sizeof(RetBuffer);
 if (WriteToFlash)
  {
  pDevice->Timeout += EXTRA_TIME_FOR_SETUP_DATA;
  Error = SendPacketTwoResponses(pDevice, Buffer, Total, RetBuffer,
&NumBytes,
          TRUE, FALSE,
          0, NULL,
          30000, TRUE, TRUE);
  pDevice->Timeout -= EXTRA_TIME_FOR_SETUP_DATA;
  }
 else
  {
  Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
  }
 //if (Error)
 // return Error;
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 if (NumBytes)
  return *((short int *) (RetBuffer+PACKET_HEADER_SIZE));
 else
  return HEIE_ZERO_BYTES_RECEIVED;
 }

__declspec(dllexport) int HEIReadSerialPortSetupEx(HEIDevice *pDevice, BYTE
Port, SerialSetup *pSetup)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int NumBytes;
 //Port = (Port - 1) << 4;
 Buffer[DataOffset] = FUN_SERIAL_PORT;
 Buffer[DataOffset+1] = SPF_READ_SETUP + 0x80; //Port;
 Buffer[DataOffset+2] = Port-1;
 Buffer[DataOffset+3] = 0;
 Buffer[DataOffset+4] = 0;
 Total = DataOffset+5;
 NumBytes = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 //if (Error) return Error;
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 if (NumBytes)
  {
  // Copy data into user buffer.
  memcpy(pSetup, RetBuffer+PACKET_HEADER_SIZE, sizeof(SerialSetup));
  return 0;
  }
 else
  return HEIE_ZERO_BYTES_RECEIVED;
 }

__declspec(dllexport) int HEIGetTXLeftEx(HEIDevice *pDevice, BYTE Port, WORD
*pLeft)
 {
 BYTE Buffer[200];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 //int Retval;
 int NumBytes;
 //Port = (Port - 1) << 4;
 Buffer[DataOffset] = FUN_SERIAL_PORT;
 Buffer[DataOffset+1] = SPF_TX_LEFT + 0x80; //Port;
 Buffer[DataOffset+2] = Port-1;
 Total = DataOffset+3;
 NumBytes = sizeof(RetBuffer);

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes, TRUE,
FALSE);
 //if (Error) return Error;
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 //Retval = Error;
 if (NumBytes)
  {
  *pLeft = *((WORD *) (RetBuffer+PACKET_HEADER_SIZE+2));
  return *((short int *) (RetBuffer+PACKET_HEADER_SIZE));
  }
 else
  return HEIE_ZERO_BYTES_RECEIVED;
 }
__declspec(dllexport) int HEIAccessComm(HEIDevice *pDevice, WORD
SendDataSize, BYTE *pSendData, WORD *pReturnDataSize, BYTE *pReturnData)
 {
 BYTE Buffer[1500];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 WORD *pWord;
 int Error;
 int NumBytes;
 int Retval;
 Buffer[DataOffset] = FUN_SERIAL_PORT;
 Buffer[DataOffset+1] = SPF_ACCESS_COMM;
 pWord = (WORD *) &Buffer[DataOffset+2];
 *pWord = SendDataSize;
 if (SendDataSize > (sizeof(Buffer) - DataOffset - 4))
  return HEIE_DATA_TOO_LARGE;
 memcpy(Buffer+DataOffset+4, pSendData, SendDataSize);
 Total = DataOffset+4+SendDataSize;
 NumBytes = sizeof(Buffer);

 Error = _SendPacket(pDevice, Buffer, Total, Buffer, &NumBytes, TRUE,
FALSE);
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  short int *pInt = (short int *) (Buffer+PACKET_HEADER_SIZE);
  short int *pNumReturned = (short int *) (Buffer+PACKET_HEADER_SIZE+2);
  if (*pInt)
   Retval = *pInt;
  if (pReturnData && pReturnDataSize)
   {
   if (*pNumReturned > *pReturnDataSize)
    {
    Retval = HEIE_BUFFER_TOO_SMALL;
    }
   else
    {
    (*pReturnDataSize) = *pNumReturned;
    }
   memcpy(pReturnData, Buffer+PACKET_HEADER_SIZE+4, *pReturnDataSize);
   }
  }
 else
  Retval = HEIE_ZERO_BYTES_RECEIVED;
 return Retval;
 }

__declspec(dllexport) int HEIWriteEZethernetPgmSpace(HEIDevice *pDevice,
BYTE *pData, WORD SizeofData)
 {
 BYTE Buffer[600];
 BYTE RetBuffer[200];
 WORD DataOffset = pDevice->DataOffset;
 WORD *pWord;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;
 Buffer[DataOffset] = (BYTE)FUN_USER_CONFIG_PANEL; /* This is the function
code! */
 Buffer[DataOffset+1] = 0;
 pWord = (WORD *) &Buffer[DataOffset+2];
 Total = DataOffset+4+SizeofData;
 // FYI: Incoming size should never be greater than 316 bytes.
 //      60 bytes control + 255 Max AVG packet size + 1 byte for
 //      the start character.
 if (Total > sizeof(Buffer) || SizeofData > 316)
  return HEIE_DATA_TOO_LARGE;
 (void)memcpy(&Buffer[DataOffset+4], pData, SizeofData);
 NumBytes = sizeof(RetBuffer);

 pDevice->Timeout += EXTRA_TIME_FOR_SETUP_DATA;
 Error = SendPacketTwoResponses(pDevice, Buffer, Total, RetBuffer,
&NumBytes,
         TRUE, FALSE,
         0, NULL,
         30000, TRUE, TRUE);
 pDevice->Timeout -= EXTRA_TIME_FOR_SETUP_DATA;
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  short int *pInt = (short int *) (RetBuffer+PACKET_HEADER_SIZE);
  if (*pInt)
   Retval = *pInt;
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;
  }
 return Retval;
 }

/*
** ERM Functions.
*/
#define FUN_COMMAND  6
#define FUN_READ_DATA 7
#define FUN_WRITE_DATA 8
#define FUN_STATUS_INWORK 1
#define FUN_STATUS_DONE  2
#define FUN_STATUS_ERROR 3
__declspec(dllexport) int HEIWriteERMData(HEIDevice *pDevice, WORD Base,
WORD Slot, BYTE DataType, BYTE *pData, WORD NumBytes, WORD Offset)
 {
 WORD Data[6];
 WORD *pOffset;
 WORD *pExtended;
 WORD *pNumBytes;
 int Index = 0;
 // Common header
 Data[Index++] = 0;      // Function + Status (ClearFunction until all other
data is written)
 Data[Index++] = 0;      // Error
 // Function specific header
 Data[Index++] = DataType;    // Data type
 pOffset = (WORD *) &Data[Index++]; // Pointer to Offset
 pNumBytes = (WORD *) &Data[Index++];// Pointer to num bytes
 pExtended = (WORD *) &Data[Index++]; // Pointer to extended
 *pOffset = Offset;
 *pNumBytes = 256;
 *pExtended = 0;

 while (NumBytes)
  {
  int Error;
  //memcpy(&Data[11], pOutputData, *pNumBytes);
  if (*pNumBytes > NumBytes)
   *pNumBytes = NumBytes;
  Data[0] = 0;
  Data[1] = 0;
  // Write Header first.
  Error = HEIWriteSharedRAM(pDevice, Base, Slot, 0x30 + 0x8000,
sizeof(Data), (BYTE *) Data);
  if (Error)
   {
   //printf("\nError %d (0x%X) from HEIWriteSharedRAM", Error, Error);
   return Error;
   }
  // Next write data.
  Error = HEIWriteSharedRAM(pDevice, Base, Slot, 0x30+sizeof(Data) + 0x8000,
*pNumBytes, pData);
  if (Error)
   {
   //printf("\nError %d (0x%X) from HEIWriteSharedRAM", Error, Error);
   return Error;
   }
  // Now write the REAL command.
  Data[0] = FUN_WRITE_DATA;
  Error = HEIWriteSharedRAM(pDevice, Base, Slot, 0x30+ 0x8000, 1, (BYTE *)
Data);
  if (Error)
   {
   //printf("\nError %d (0x%X) from HEIWriteSharedRAM", Error, Error);
   return Error;
   }
  else
   {
   // Wait for it to complete.
   DWORD StartTime = HEIIGetCounter();
   BOOL Done = FALSE;
   do
    {
    BYTE bData[4];
    Error = HEIReadSharedRAM(pDevice, Base, Slot, 0x30+ 0x8000, 4, (BYTE *)
bData);
    if (Error)
     {
     //printf("\nError %d (0x%X) from HEIReadSharedRAM", Error, Error);
     return Error;
     }
    else
     {
     if ((bData[1] & 0xFF) == FUN_STATUS_DONE)
      {
      Done = TRUE;
      }
     else if ((bData[1] & 0xFF) == FUN_STATUS_ERROR)
      {
      return bData[2];  // Return Error
      }
     }
    } while (!Done && TimeDiff(StartTime, HEIIGetCounter()) <
pDevice->Timeout);
   if (!Done)
    {
    //printf("\nTimeout waiting for request to complete.");
    return HEIE_TIMEOUT;
    }
   }
  pData += *pNumBytes;
  (*pOffset) += *pNumBytes;
  NumBytes -= *pNumBytes;
  }
#if 0
 if ((DataType == DATA_OUTPUT) && (Flags & 0x01))
  {
  return WPLCDoERMCommand(Base, Slot, COMMAND_PROCESS_IO, 0, 0);
  }
#endif
 return 0;
 }
__declspec(dllexport) int HEIReadERMData(HEIDevice *pDevice, WORD Base, WORD
Slot, BYTE DataType, BYTE *pData, WORD NumBytes, WORD Offset)
 {
 WORD Data[6];
 WORD *pOffset;
 WORD *pNumBytes;
 WORD *pExtended;
 int Index = 0;
 // Common header
 Data[Index++] = 0;      // Function + Status (ClearFunction until all other
data is written)
 Data[Index++] = 0;      // Error
 // Function specific header
 Data[Index++] = DataType;    // Data type
 pOffset = (WORD *) &Data[Index++]; // Pointer to Offset
 pNumBytes = (WORD *) &Data[Index++];// Pointer to num bytes
 pExtended = (WORD *) &Data[Index++]; // Pointer to extended
 *pOffset = Offset;
 *pNumBytes = 256;
 *pExtended = 0;
 //RETAILMSG(1, (TEXT("\r\nWPLCReadERMData Base: %d Slot: %d  Type: %d  Num:
%d"), Base, Slot, DataType, NumBytes));
 while (NumBytes)
  {
  int Error;
  Data[0] = 0;
  Data[1] = 0;
  if (*pNumBytes > NumBytes)
   {
   *pNumBytes = NumBytes;
   }
  Error = HEIWriteSharedRAM(pDevice, Base, Slot, 0x30+0x8000, sizeof(Data),
(BYTE *) Data);
  if (Error)
   {
   //printf("\nError %d (0x%X) from HEIWriteSharedRAM", Error, Error);
   return Error;
   }
  // Now write the REAL command.
  Data[0] = FUN_READ_DATA;
  Error = HEIWriteSharedRAM(pDevice, Base, Slot, 0x30+0x8000, 2, (BYTE *)
Data);
  if (Error)
   {
   //printf("\nError %d (0x%X) from HEIWriteSharedRAM", Error, Error);
   return Error;
   }
  else
   {
   // Wait for it to complete.
   DWORD StartTime = HEIIGetCounter();
   BOOL Done = FALSE;
   do
    {
    BYTE bData[4];
    Error = HEIReadSharedRAM(pDevice, Base, Slot, 0x30+0x8000, 4, bData);
    if (Error)
     {
     //printf("\nError %d (0x%X) from HEIReadSharedRAM", Error, Error);
     return Error;
     }
    else
     {
   //RETAILMSG(1, (TEXT("\r\nbData: 0x%X 0x%X 0x%X 0x%X"), bData[0],
bData[1], bData[2], bData[3]));
     //if (((Data[0]>>8) & 0xFF) == FUN_STATUS_DONE)
     if (bData[1] == FUN_STATUS_DONE)
      {
      // Read the rest of the data.
      Error = HEIReadSharedRAM(pDevice, Base, Slot,
0x30+sizeof(Data)+0x8000, *pNumBytes, pData);
      if (Error)
       {
       //printf("\nError %d (0x%X) from HEIReadSharedRAM", Error, Error);
       return Error;
       }
      Done = TRUE;
      }
     //else if (((Data[0]>>8) & 0xFF) == FUN_STATUS_ERROR)
     else if (bData[1] == FUN_STATUS_ERROR)
      {
      return Data[2];
     // memcpy(pInputData, &Data[11], *pNumBytes);
      }
     }
    } while (!Done && TimeDiff(StartTime, HEIIGetCounter()) <
pDevice->Timeout);
   if (!Done)
    {
    //printf("\nTimeout waiting for request to complete.");
    return HEIE_TIMEOUT;
    }
   }
  pData += *pNumBytes;
  (*pOffset) += *pNumBytes;
  NumBytes -= *pNumBytes;
  }
 return 0;
 }
__declspec(dllexport) int HEIDoERMCommand(HEIDevice *pDevice, WORD Base,
WORD Slot, WORD Command)
 {
 DWORD StartTime;
 WORD Data[3];
 int Index = 0;
 int Error;
 // Common header
 Data[Index++] = 0; // Command and Status (Set Command to zero until rest of
data is written)
 Data[Index++] = 0;      // Error

 // Function specific header
 Data[Index++] = Command;
 Error = HEIWriteSharedRAM(pDevice, Base, Slot, 0x30 + 0x8000, sizeof(Data),
(BYTE *) Data);
 if (Error)
  {
  //printf("\nError %d (0x%X) from HEIWriteSharedRAM", Error, Error);
  return Error;
  }
 // Now write the REAL command.
 Data[0] = FUN_COMMAND;
 Error = HEIWriteSharedRAM(pDevice, Base, Slot, 0x30+0x8000, 2, (BYTE *)
Data);
 if (Error)
  {
  //printf("\nError %d (0x%X) from HEIWriteSharedRAM", Error, Error);
  return Error;
  }
  // Wait for it to complete.
 StartTime = HEIIGetCounter();
 while (TimeDiff(StartTime, HEIIGetCounter()) < pDevice->Timeout)
  {
  BYTE bData[4];
  Error = HEIReadSharedRAM(pDevice, Base, Slot, 0x30+0x8000, 4, (BYTE *)
bData);
  if (!Error)
   {
   if ((bData[1] & 0xFF) == FUN_STATUS_DONE)
    return 0;
   else if ((bData[1] & 0xFF) == FUN_STATUS_ERROR)
    return bData[2];
   }
  }
 return HEIE_TIMEOUT;
 }

__declspec(dllexport) int HEIDoERMCommandEx(HEIDevice *pDevice, WORD Base,
WORD Slot, WORD Command, BYTE *pExtra, WORD ExtraLen)
 {
 DWORD StartTime;
 BYTE Data[300];
 int Index = 0;
 int Error;
 WORD *pCommand;
 BOOL Done;
 // Common header
 Data[Index++] = 0; // Command and Status (Set Command to zero until rest of
data is written)
 Data[Index++] = 0;      // Error
 Data[Index++] = 0; // Command and Status (Set Command to zero until rest of
data is written)
 Data[Index++] = 0;      // Error

 // Function specific header
 pCommand = (WORD *) &Data[Index];
 *pCommand = Command;
 Index += 2;
 memcpy(&Data[Index], pExtra, ExtraLen);
 Error = HEIWriteSharedRAM(pDevice, Base, Slot, 0x30 + 0x8000,
(WORD)(ExtraLen + 6), Data);
 if (Error)
  {
  //printf("\nError %d (0x%X) from HEIWriteSharedRAM", Error, Error);
  return Error;
  }
 // Now write the REAL command.
 Data[0] = FUN_COMMAND;
 Data[1] = 0;
 Error = HEIWriteSharedRAM(pDevice, Base, Slot, 0x30+0x8000, 2, (BYTE *)
Data);
 if (Error)
  {
  //printf("\nError %d (0x%X) from HEIWriteSharedRAM", Error, Error);
  return Error;
  }
  // Wait for it to complete.
 Done = FALSE;
 StartTime = HEIIGetCounter();
 do
  {
  BYTE bData[4];
  Error = HEIReadSharedRAM(pDevice, Base, Slot, 0x30+0x8000, 4, bData);
  if (!Error)
   {
   if (bData[1] == FUN_STATUS_DONE)
    Done = TRUE;
   else if (bData[1] == FUN_STATUS_ERROR)
    return (int) (((WORD) bData[2]) + (((WORD) bData[3]) << 8));
   }
  } while (!Done && TimeDiff(StartTime, HEIIGetCounter()) <
pDevice->Timeout);
 if (!Done)
  return HEIE_TIMEOUT;
 return 0;
 }

NODELIST *EZGetNodeList(unsigned short int *TotalEZ)
{
    static NODELIST EZList[200];
    static HEIDevice HEIDevices[100];
    static HEITransport   TP;
    unsigned short int i, j;   // Index variables
    int Error, MaxDevices, MaxEZDevices;
    WORD  Timeout   = 100;
    WORD  Retrys    = 2;
    WORD  SizeofData;
    BOOL  Broadcast = FALSE;
    BYTE  Data[500];
 BYTE *pData = Data;
    DeviceDef dd;
  WORD NumDevices;
    HEITransport *tp = &TP;
    ENetAddress  *pSourceAddress = (ENetAddress *)NULL;
 tp->Transport = HEIT_WINSOCK;
    tp->Protocol  = HEIP_IPX;
    *TotalEZ = 0;   // Set to zero until proven otherwise.
 Error = HEIOpenTransport(tp, HEIAPIVERSION, pSourceAddress);
    if (Error)
 {
        //printf("Error returned from HEIOpenTransport()\n");
        return (NODELIST *)NULL;
 }
    MaxDevices   = sizeof(HEIDevices) / sizeof(HEIDevice);
    MaxEZDevices = sizeof(EZList)     / sizeof(NODELIST);
 NumDevices = MaxEZDevices;
 Error = HEIQueryDevices(tp, HEIDevices, &NumDevices, HEIAPIVERSION);
 if (Error)
 {
        //printf("Error returned from HEIQueryDevices()\n");
        (void)HEIClose();
        return (NODELIST *)NULL;
 }

    j = 0;
    for (i = 0; i < NumDevices; i++)
    {
        if (i > MaxDevices)
        {
            goto ReturnIncompleteList;
        }
        Error = HEIOpenDevice(tp, &HEIDevices[i], HEIAPIVERSION, Timeout,
Retrys, Broadcast);
        if (Error)
        {
            //printf("IsDeviceEZEthernet: Error %d returned from
HEIOpenDevice\n", Error);
            return (NODELIST *)NULL;
        }
     Error = HEIReadDeviceDef(&HEIDevices[i], (BYTE *) &dd, sizeof(dd));
        if (Error)
        {
            //printf("IsDeviceEZEthernet: Error returned from
HEIReadDeviceDef\n");
            goto ErrorHandler;
        }
        if (dd.ModuleType == MT_AVG_DISP)
        {
            if (j >= MaxEZDevices)
                goto ErrorHandler;
            SizeofData = sizeof(WORD);
            Error = HEIReadSetupData( &HEIDevices[i], DT_NODE_NUMBER, pData,
&SizeofData);
      if (Error)
      {
                //printf("Error %d returned from HEIReadSetupData1\n",
Error);
                goto ErrorHandler;
            }
      else
            {
                 (void)memcpy(EZList[j].Node_ID, pData, sizeof(WORD));
      }
            // Get the Node Name
      SizeofData = sizeof(EZList[0].Name);
            Error = HEIReadSetupData(&HEIDevices[i], DT_NODE_NAME, pData,
&SizeofData);
      if (Error)
      {
                //printf("Error returned from
HEIReadSetupData2\n");
                goto ErrorHandler;
            }
            else
            {
             (void)memcpy(EZList[j].Name, pData, SizeofData);
            }
            EZList[j].pDevice = &HEIDevices[i];
            j++;
        }
        else
        {
            // Close the device since it is not an EZ_Ethernet.
            (void)HEICloseDevice(&HEIDevices[i]);
        }
    }   // End of for

    if (j == 0)
    {
        goto ErrorHandler;
    }
    else
    {
        (void)HEIClose();
        *TotalEZ = j;
        return EZList;
    }

    ReturnIncompleteList:
        // If we have process the maximum number of devices we can
        // do, return a list of what we got.
        (void)HEIClose();
        *TotalEZ = j;
     return EZList;
    ErrorHandler:
        (void)HEICloseDevice(&HEIDevices[i]);
        (void)HEIClose();
     return (NODELIST *)NULL;
}

BOOL EZSendPacket(HEIDevice *pDevice, PGM_BUF *pBuffer, BYTE *Error_message,
unsigned short int Len)
{
    int Error;
#if TC_DEBUG
    int i;
    printf("EZSendPacket: Incoming buffer has:\n");
    for (i = 0; i < Len; i++)
        printf("%c", pBuffer->PgmData[i]);
    printf("\n");
#endif
    Error = HEIWriteEZethernetPgmSpace(pDevice, (BYTE *)pBuffer->PgmData,
Len );
 switch (Error)
    {
        case HEIE_DATA_TOO_LARGE:
        {
            (void)memcpy(&Error_message, "Message size too large", 81);
            return FALSE;
        }

        case HEIE_ZERO_BYTES_RECEIVED:
        {
            (void)memcpy(&Error_message, "Attempted to send zero-length
message", 81);
             return FALSE;
        }
        case -1:
        {
            // printf("Error %X returned from
HEIWriteEZethernetPgmSpace!\n", Error);
             (void)memcpy(&Error_message, "HEIWriteEZethernetPgmSpace call
failed with -1", 81);
             return FALSE;
        }
        case NO_ERROR:
        {
              //printf("Successfull send from
HEIWriteEZethernetPgmSpace\n");
              Error_message[0] = '\0';
              return TRUE;
        }

        default:
        {
             //printf("Error %X returned from
HEIWriteEZethernetPgmSpace!\n", Error);
             (void)memcpy(&Error_message, "HEIWriteEZethernetPgmSpace call
failed with unknown error", 81);
             return FALSE;
        }
    }
 return TRUE;
}

int WPLCWriteERMData(HEIDevice *pDevice, WORD Base, WORD Slot, BYTE
DataType, BYTE *pData, WORD NumBytes, WORD Offset)
 {
 return HEIWriteERMData(pDevice, Base, Slot, DataType, pData, NumBytes,
Offset);
 }
int WPLCReadERMData(HEIDevice *pDevice, WORD Base, WORD Slot, BYTE DataType,
BYTE *pData, WORD NumBytes, WORD Offset)
 {
 return HEIReadERMData(pDevice, Base, Slot, DataType, pData, NumBytes,
Offset);
 }
int WPLCDoERMCommand(HEIDevice *pDevice, WORD Base, WORD Slot, WORD Command)
 {
 return HEIDoERMCommand(pDevice, Base, Slot, Command);
 }
int WPLCDoERMCommandEx(HEIDevice *pDevice, WORD Base, WORD Slot, WORD
Command, BYTE *pExtra, WORD ExtraLen)
 {
 return HEIDoERMCommandEx(pDevice, Base, Slot, Command, pExtra, ExtraLen);
 }

__declspec(dllexport) int SetCRCMode(int Mode)
 {
 int Old = DoCRC;
 DoCRC = Mode;
 return Old;
 }

/* CONFIG DATA ACCESS */
__declspec(dllexport) int HEIReadConfigData(HEIDevice *pDevice, BYTE *pData,
WORD *DataSize)
 {
 BYTE Buffer[100];
 BYTE RetBuffer[1200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;

 Buffer[DataOffset] = FUN_READ_CONFIG_DATA; /* This is the function code! */
 Total = DataOffset+1;
 if (pData && *pData == 0xB1)
  {
  Buffer[DataOffset+1] = *pData;
  Total++;
  }
 NumBytes = sizeof(RetBuffer);
 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes,
(pDevice->ParallelPackets) ? FALSE : TRUE, TRUE);
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  short int *pInt = (short int *) &RetBuffer[PACKET_HEADER_SIZE];
  NumBytes -= PACKET_HEADER_SIZE;
  NumBytes -= 2;
  if ((WORD) NumBytes > *DataSize)
   {
   Retval = HEIE_BUFFER_TOO_SMALL;
   NumBytes = *DataSize;
   }
  if (*pInt)
   Retval = (*pInt) | 0x8000;
  memcpy(pData, RetBuffer+PACKET_HEADER_SIZE+2, NumBytes);
  (*DataSize) = NumBytes;
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;
  (*DataSize) = 0;
  }
 return Retval;
 }

__declspec(dllexport) int HEIWriteConfigData(HEIDevice *pDevice, BYTE
*pData, WORD SizeofData, BYTE *pReturnData, WORD *pSizeofReturnData)
 {
 BYTE Buffer[1200];
 BYTE RetBuffer[1200];
 WORD DataOffset = pDevice->DataOffset;
 WORD Total;
 int Error;
 int Retval;
 int NumBytes;
 Buffer[DataOffset] = FUN_WRITE_CONFIG_DATA;    /* This is the function
code! */

 Total = DataOffset+1+SizeofData;
 if (Total > sizeof(Buffer))
  return HEIE_DATA_TOO_LARGE;
 memcpy(Buffer+DataOffset+1, pData, SizeofData);
 NumBytes = sizeof(RetBuffer);
 //NumBytes = *pSizeofReturnData;

 Error = _SendPacket(pDevice, Buffer, Total, RetBuffer, &NumBytes,
(pDevice->ParallelPackets) ? FALSE : TRUE, TRUE);
 /* Check for error and not warning. */
 if (Error && !(Error & HEIW_FIRST_WARNING))
  return Error;
 Retval = Error;
 if (NumBytes)
  {
  short int *pInt = (short int *) &RetBuffer[PACKET_HEADER_SIZE];
  if (pReturnData && pSizeofReturnData)
   {
   NumBytes -= PACKET_HEADER_SIZE;
   NumBytes -= 2;
   if ((WORD) NumBytes > *pSizeofReturnData)
    {
    Retval = HEIE_BUFFER_TOO_SMALL;
    NumBytes = *pSizeofReturnData;
    }
   memcpy(pReturnData, RetBuffer+PACKET_HEADER_SIZE+2, NumBytes);
   (*pSizeofReturnData) = NumBytes;
   }
  if (*pInt)
   Retval = (*pInt) | 0x8000;
  }
 else
  {
  Retval = HEIE_ZERO_BYTES_RECEIVED;
  if (pSizeofReturnData)
   (*pSizeofReturnData) = 0;
  }
 return Retval;
 }

/*
**
**  HOST ETHERNET INTERFACE (HEI) - HEADER FILE
**
** Copyright 1996-2001 - Host Automation Products, Inc.
*
*/
#if !defined(__HEI_H)
#define __HEI_H

/* Force structure alignment on single byte boundary */
#pragma pack(1)
#if !defined(P_ERMA) & !defined(P_ECOM)  & !defined(EBC) & !defined(P_ERMA)
& !defined(BOOTER) & !defined(PROFIBUS)
typedef struct
 {
 unsigned IgnoreUserMain : 1;
 unsigned IgnoreVbUserMain : 1;
 unsigned IgnoreDebugMsg : 1;
 unsigned UnusedBits : 29;
 BYTE UnusedBytes[28];
 } StartupSettings;
#endif
typedef struct
 {
 WORD SizeofEthernetStats;
 DWORD MissedFrameCount;
 DWORD TransmitCollisionCount;
 DWORD DiscardedPackets;
 DWORD BadCRCCount;

 DWORD UnknownTypeCount;
 DWORD SendErrorCount;
 } EthernetStats;
typedef struct
 {
 BYTE Version;
 BYTE Bytes2Follow;

#if defined (ANSI_C)
 BYTE UnusedBytess[16];       /* Support Info */
#else
 BYTE SUP_FUN_POLLING     : 1;   /* Polling one base */
 BYTE SUP_FUN_READ_VER_INFO   : 1;    /* Version Info */
 BYTE SUP_FUN_READ_SUPPORT_INFO  : 1;   /* Support Info */
 BYTE SUP_FUN_READ_DEVICE_INFO  : 1;   /* Device Info  */
 BYTE SUP_FUN_POLLING_ALL   : 1;    /* Polling all bases (returns ethernet
address) */
 BYTE SUP_FUN_WRITE_IO    : 1;   /* Write IO base */
 BYTE SUP_FUN_READ_IO    : 1;   /* Read IO Base */
 BYTE SUP_FUN_READ_BASE_DEF   : 1;    /* ReadBaseDef */

 BYTE SUP_FUN_ENUM_SETUP_DATA  : 1;   /* Enumerate setup data */
 BYTE SUP_FUN_READ_SETUP_DATA     : 1;   /* Read setup data */
 BYTE SUP_FUN_WRITE_SETUP_DATA  : 1;   /* Write setup data */
 BYTE SUP_FUN_DELETE_SETUP_DATA  : 1;    /* Delete setup data */
 BYTE SUP_FUN_READ_ETHERNET_STATS : 1;    /* Read ethernet statistics */
 BYTE SUP_FUN_PET_LINK    : 1;    /* Used to keep the link sense timer from
firing in the absense of ReadIO or WriteIO messages */
 BYTE SUP_FUN_ADDRESSED_BROADCAST : 1;    /* Used to broadcast to a
particular ethernet address. */
 BYTE SUP_FUN_READ_MODULE_STATUS  : 1;   /* Read module status short BYTEs
*/

 BYTE SUP_FUN_EXTENDED    : 1;   /* Extended function */
 BYTE SUP_FUN_QUERY_SETUP_DATA  : 1;   /* Query for particular data
type/value */
 BYTE SUP_FUN_INIT_BASE_DEF    : 1;   /* Initialize base def from backplane.
*/
 BYTE SUP_FUN_DATA_BROADCAST   : 1;   /* Broadcast to a particular data type
*/
 BYTE SUP_FUN_CCM_REQUEST   : 1;   /* Perform CCM Request */
 BYTE SUP_FUN_KSEQ_REQUEST   : 1;   /* Perform KSEQ Request */
 BYTE SUP_FUN_BACKPLANE_REQUEST  : 1;   /* Perform backplane request */
 BYTE SUP_FUN_WRITE_BASE_DEF   : 1;   /* Write Base Def */

 BYTE SUP_FUN_EXTEND_RESPONSE  : 1;   /* Extends the response packet. */
 BYTE SUP_FUN_ACK     : 1;   /* Acknowledge */
 BYTE SUP_FUN_NAK     : 1;   /* NOT Acknowledge */
 BYTE SUP_FUN_RESPONSE     : 1;   /* Response */
 BYTE SUP_FUN_SERIAL_PORT   : 1;   /* Execute serial port function (see
below) */
 BYTE SUP_FUN_WRITE_MEMORY   : 1;   /* Write a particular memory type */
 BYTE SUP_FUN_READ_MEMORY   : 1;   /* Read a particular memory type */
 BYTE SUP_FUN_ENUM_MEMORY   : 1;   /* Get list of all memory types */
 BYTE SUP_FUN_READ_SHARED_RAM  : 1;   /* Read shared ram */
 BYTE SUP_FUN_WRITE_SHARED_RAM  : 1;   /* Write shared ram */
 BYTE SUP_FUN_ACCESS_MEMORY   : 1;   /* Access (read/write) multiple memory
types */
 BYTE SUP_FUN_COMM_RESPONSE   : 1;   /* Response to PLC generated COMM
request */
 BYTE SUP_FUN_COMM_REQ_ACK   : 1;   /* Function from PLC generated COMM
request */
 BYTE SUP_FUN_WRITE_IO_NO_READ  : 1;   /* Write IO base with returned read
*/
 BYTE SUP_FUN_COMM_NO_REQ_ACK  : 1;  /* Function from PLC generated COMM
request */
 BYTE SUP_FUN_RUN_PROGRAM   : 1;   /* Function to execute a program */
 BYTE SUP_FUN_REMOTE_API    : 1;  /* Function to execute a function on
remote device */
 BYTE SUP_FUN_NOTIFY     : 1;  /* Indicates a notification */
 BYTE SUP_FUN_COMPLETION    : 1;  /* Indicates completion of some activity
*/
 BYTE SUP_FUN_SET_OS_LOAD   : 1;  /* Set Load OS Parm. */
 BYTE SUP_FUN_REBOOT     : 1;  /* Reboot OS   */
 BYTE SUP_FUN_EXTEND_RESPONSE_FIX : 1; /* Fixed version that extends the
response packet. */
 BYTE SUP_NEW_STYLE_IO    : 1; /* This device supports new style I/O
requests */
 BYTE SUP_HOT_SWAP      : 1; /* True if this device supports hot swap */
 BYTE SUP_TCP_IP      : 1;  /* TRUE if this device supports TCP/IP */
 BYTE SUP_HTTP       : 1;  /* TRUE if this device supports HTTP */
 BYTE Reserved       : 6;

 BYTE UnusedBytes[9];       /* Unused */
#endif
 } SupportDef;

/* Defines for Flags in WPLCSystemInformation structure */
#define WPLC_FLAG_BATT_LOW 0x01
/* Masks for LED indicator */
#define WPLC_LED_POWER 0x01
#define WPLC_LED_RUN  0x02

typedef struct
 {
 DWORD Flags;   /* Bit 0: Battery Low indicator.  */
        /* Bit 1-31: Unused      */
 DWORD RAMSize;   /* Total size of RAM in WinPLC */
 DWORD FlashSize;  /* Total size of Flash memory in WinPLC */
 DWORD BattRAMSize; /* Total size of Battery-backed ram in WinPLC */
 DWORD DipSwitches; /* Status of dip switches */
        /* Note: Dip Switches #6 & #7 are reserved for system use. */
 DWORD LEDs;    /* LED status indicator (see WPLC_LED_XXXX defines) */
 DWORD OSSize;   /* Size of the WinPLC OS Image */
 DWORD FFSTotal;  /* Total size of the WinPLC flashed based file system */
 DWORD FFSFree;   /* Free size of the WinPLC flashed based file system */
 DWORD RAMPercentFree; /* Percent of RAM that is free. */
 DWORD RAMPhysicalFree; /* Physical RAM that is free.  */
 DWORD VendorID;   /* Vendor ID from the WinPLC */
 DWORD CPUClockFrequency;
 BYTE  ENetAddress[6];
 BYTE Unused[198];
 } WPLCSystemInformation;


/* ERM Defs */
#define BIT_INPUT  0
#define BIT_OUTPUT 1
#define WORD_INPUT 2
#define WORD_OUTPUT 3
/* sERMDevice (128 bytes each) */
typedef struct
 {
 BYTE AddressMode;  /* Defines format of address field (see AM_XXX
below)    */
 BYTE Protocol;   /* HEIP_HOST, HEIP_IPX, or HEIP_IP, 0 == Unused      */
 struct
  {
  union
   {
   /* Use this for AM_ETHER addressing (Protocol: HEIP_IPX or HEIP_HOST) */
   BYTE EtherAddr[6];  /* Ethernet network address */
   /* Use this for AM_NODENUM addressing (Protocol: HEIP_IPX or HEIP_HOST or
HEIP_IP) */
   DWORD Nodenum;
   /* Use this for AM_IPADDR addressing (Protocol: HEIP_IPX or HEIP_HOST or
HEIP_IP) */
   BYTE IPAddr[4];
#if defined (ANSI_C)
   } AM;
#else
   };
#endif
  BYTE Netnum[4]; /* Used for HEIP_IPX protocol; HEIP_IP   */
  WORD Port;   /* Used for HEIP_IPX and HEIP_IP protocols */
  union
   {
   BYTE FrameType; /* Used for HEIP_IPX protocol (See FT_XXXX) */
   BYTE GatewayAddress[4]; /* Gateway to use for this device (0's for no
gateway) */
#if defined (ANSI_C)
   } AM2;
#else
   };
#endif
  /* BYTE Reserved[3];*/
  } Address;
 WORD Timeout;      /* Timeout time for this device           */
 WORD Retrys;      /* Number of time to retry a request before reporting
error.   */
 BYTE ModuleIDs[32];    /* Module ID's for each slot in the device       */
 WORD Flags;       /* See ERM_FLAG_??? defines            */
 WORD DataOffsets[4];    /* Data offsets for each type (BIT_INPUT,
BIT_OUTPUT,    */
           /* WORD_INPUT, WORD_OUTPUT) if with a PLC        */
 WORD DataSizes[4];    /* Data sizes (in bytes) for each type if with a
PLC    */
 WORD WatchDog;      /* Watchdog timeout value to use for this device     */
 WORD PetFrequency;    /* Freq to pet the device to keep WatchDog from
firing   */
           /* Specified in milliseconds.  If zero no pets will be done  */
 WORD FailuresBeforeStandby; /* Number of consecutive failures to put device
in     */
           /* standby mode.                */
 BYTE Reserved[50];    /* Reserved (set to zero)             */
 } sERMDevice;
/* Address mode 0 is undefined */
#define AM_NODENUM 1
#define AM_NAME    2  /* Not supported in ERM module. */
#define AM_IPADDR  3
#define AM_ETHER   4
/* Interface defines */
#define IF_UNDEFINED  0 /* ERM I/F not defined / detected         */
#define IF_PLC    1 /* ERM will use a PLC style interface        */
#define IF_WINPLC   2 /* ERM will use a WinPLC style interface       */
#define ERM_FLAG_IGNORE_WARNINGS  1  /* If set, warnings from this device
are ignored */
#define ERM_FLAG_AUTO_HOT_SWAP  2  /* If set, terminator hot swap is
automatic   */
/* Frame type defines */
#define FT_802_2       1
#define FT_802_3       2
#define FT_ETHER_II    3

typedef struct sERMConfig
 {
 BYTE Version;      /* Version of sERMConfig 0=Unconfigured; 1= Current
Version */
 BYTE Interface;     /* See IF_XXX above.              */
 WORD PLCAddresses[4];   /* Address for each type. (BIT_INPUT,
BIT_OUTPUT,    */
           /* WORD_INPUT, WORD_OUTPUT) if with a PLC       */
 WORD PLCDataSizes[4];   /* Size (in bytes) for each type if with a
PLC.     */
 DWORD StandbyCycleTime;   /* Time to wait when a module is not responding
before      */
           /* trying to access the module again        */
           /* If zero, the module will not be accessed again    */
 DWORD NotSupportedCycleTime; /* Time to wait when a module is not supported
before       */
           /* trying to access the module again        */
           /* If zero, the module will not be accessed again    */
 WORD AssumePLCScanTime;   /* PLC Scan time to assume for timeout purposes
if zero,       */
           /* default is used               */
 BYTE Unused[228];
 } sERMConfig;
#define MAX_ERM_DEVICES  16

typedef struct sERMDeviceInfo
 {
 BYTE State;
 BYTE Supported      : 1;
 BYTE GotAddressInfo    : 1;
 BYTE ARPReplyPending    : 1;
 BYTE GotBaseDef     : 1;
 BYTE GotSupportInfo    : 1;
 BYTE GotWatchDogSetupAck  : 1;
 BYTE GotWatchDogSetupComplete : 1;
 WORD TotalRetrys;
 WORD LastError;
 } sERMDeviceInfo;

typedef struct sERMInfo
 {
 BYTE Version;      /* Version of sERMInfo 1 = current version    */
 BYTE AutoDetectedInterface; /* Interface which was auto detected by Hx-ERM
module */
 BYTE PLCType;      /* PLC Type that Hx-ERM module is in rack with   */
 BYTE BytesInUsedByERM;   /* Number of Input bytes that Hx-ERM uses     */
           /* Currently 32 Bits (4 Bytes) of Error Info    */
 BYTE BytesOutUsedByERM;   /* Number of Output bytes that Hx-ERM uses    */
           /* Currently 16 Bits (2 Bytes) of disable bits   */
 sERMDeviceInfo DeviceInfo[MAX_ERM_DEVICES];
 WORD Error;       /* Error value from ERM           */
 WORD Status;      /* Bit per device error status        */
 BYTE RunMode : 1;    /* 1 if in Run Mode; 0 if not         */
 BYTE ERMState;
 WORD MinScan;      /* Minimum scan time in ms          */
 WORD MaxScan;      /* Miximum scan time in ms          */
 DWORD TotalScans;     /* Total Number of scans          */
 DWORD TotalTime;     /* Total Time for TotalScans         */
 DWORD ReadRetrys;     /* Number of PLC Read Retrys         */
 DWORD WriteRetrys;    /* Number of PLC Write Retrys         */
 DWORD DeviceRetrys;    /* Number of Device Retrys          */
 DWORD DeviceTime;     /* Total Time spent on device comm       */
 BYTE Base;       /* Base number that Hx-ERM module is in     */
 BYTE Slot;       /* Slot number that Hx-ERM module is in     */
 BYTE EthernetAddress[6];  /* Ethernet address of controlling WinPLC (0 for
PLC) */
 BYTE Unused[113];
 } sERMInfo;
typedef struct sDevCommand
 {
 BYTE Version;      /* Version of sDevCommand 1 = current version    */
 BYTE Command;      /* Command to give to Device (see DEV_CMD_XXX values) */
 BYTE Data[254];     /* Command specific data           */
 } sDevCommand;
#define DEV_CMD_REINIT   1  /* Used to tell Device to do a
reinitialization    */
#define DEV_CMD_RESET_STATS 2  /* Used to tell Device to clear error / stat
info   */
#define DEV_CMD_RESET_ERROR 3  /* Used to clear LastError value for one or
more devices */
            /*   Data[0]: bits 0-7 correspond to devies num 0-7  */
            /*   Data[1]: bits 0-7 correspond to devies num 8-15  */

/* Hx-ERM Errors.     */
#define ERM_CONFIG_ERROR_BITS_IN_TOO_FEW     1 /* Config error: Bits In
configured not enough    */
#define ERM_CONFIG_ERROR_BITS_OUT_TOO_FEW     2 /* Config error: Bits Out
configured not enough    */
#define ERM_CONFIG_ERROR_BITS_IN_OVERLAPS_SYS_DATA  3 /* Configured Bit
Inputs overlap system input bits   */
#define ERM_CONFIG_ERROR_BITS_OUT_OVERLAPS_SYS_DATA 4 /* Configured Bit
Outputs overlap system output bits  */
#define ERM_MULTIPLE_DEVICES_WITH_SAME_NODE_NUM   5 /* More than one device
found with same node number  */
#define ERM_MULTIPLE_DEVICES_WITH_SAME_IP_ADDRESS  6 /* More than one device
foudn with same IP address   */
#define ERM_MODULE_NOT_RESPONDING       7 /* Device is not responding to a
function request   */
#define ERM_MODULE_NOT_SUPPORTED        8 /* Device not supported; may be
firmware or cfg error  */
#define ERM_MODULE_TIMEOUT          9 /* Device timed out on a function
request (after retrys) */
#define ERM_MODULE_NO_GATEWAY_ADDRESS      13 /* Gateway address needed, but
not specified     */
#define ERM_NO_SUBNET_MASK          14 /* Subnet mask needed, but not
specified      */
#define ERM_MODULE_MISMATCHED_MODULE_IDS     15 /* Configured module Id's
don't match modules in device */
#define ERM_MODULE_INCORRECT_BITS_IN      16 /* Number of bit inputs
specified is less than actual  */
#define ERM_MODULE_INCORRECT_BITS_OUT      17 /* Number of bit outputs
specified is less than actual */
#define ERM_MODULE_INCORRECT_WORDS_IN      18 /* Number of word inputs
specified is less than actual */
#define ERM_MODULE_INCORRECT_WORDS_OUT      19 /* Number of word outputs
specified is less than actual */
#define ERM_MODULE_BASE_DEF_ERROR       20 /* Invalid base def for this
device        */
#define ERM_CONFIG_MISSING          21 /* Hx-ERM hasn't been
configured         */
#define ERM_MODULE_BASE_DEF_BUFFER_OVERFLOW    22 /* Overflow of entire
BaseDefBuffer        */
#define ERM_MODULE_BASE_DEF_OVERFLOW      23 /* Overflow of previous Device
BaseDef       */
#define ERM_MODULE_WRITE_PACKET_BUFFER_OVERFLOW   24 /* Overflow of entire
WritePacketBuffer      */
#define ERM_MODULE_WRITE_PACKET_OVERFLOW     25 /* Overflow of previous
WritePacketBuffer      */
#define ERM_CONFIG_IO_BUFFER_OVERFLOW      26 /* Overflow of entire IO
buffer         */
#define ERM_CONFIG_ERROR_WORDS_IN_TOO_FEW     27 /* Config error: Words In
configured not enough    */
#define ERM_CONFIG_ERROR_WORDS_OUT_TOO_FEW    28 /* Config error: Words Out
configured not enough   */
/* ERM Backplane errors */
#define ERM_BPERROR_OBJ_NOT_FOUND           221 /* Internal backplane
error          */
#define ERM_BPERROR_UNK_PLC_FAMILY       223 /* PLC Family
unknown            */
#define ERM_BPERROR_INVALID_STATUS       224 /* Invalid backplane status
value        */
#define ERM_BPERROR_CCM_CODEERROR       225 /* Code Error returned from
PLC         */
#define ERM_BPERROR_CCM_ERROR         226 /* General Error returned from
PLC        */
#define ERM_BPERROR_TIMEOUT         227 /* Timeout on PLC backplane
request        */
#define ERM_BPERROR_NO_MORE_OBJECTS       228 /* Backplane queue
full            */
#define ERM_BPERROR_INVALID_REQUEST       231 /* Internal request
error           */
/* Serial port defines */
#define SERIAL_1_STOP_BIT 0
#define SERIAL_2_STOP_BITS  1
#define SERIAL_7_DATA_BITS 0
#define SERIAL_8_DATA_BITS 1
#define SERIAL_NO_PARITY 0
#define SERIAL_ODD_PARITY 2
#define SERIAL_EVEN_PARITY 3
#define SERIAL_SLAVE  0
#define SERIAL_MASTER  1
#define SERIAL_PROXY  1
#define SERIAL_NO_RTS  0
#define SERIAL_USE_RTS  1

typedef struct
 {
 DWORD BaudRate;    /* Baud rate to use i.e. 9600 */
          /* If Baud rate == 0 then serial port is disabled */

#if defined (ANSI_C)
 BYTE  ConfigData;
#else
 BYTE StopBits  : 1;    /* 0 == 1 Stop bit;  1 == 2 Stop bits */
 BYTE  DataBits : 1;    /* 0 == 7 Data bits;  1 == 8 Data bits */
 BYTE Parity  : 2;    /* 0 == 1 == None; 2 == Odd;  3 == Even */
 BYTE Mode  : 1;    /* 0 == Slave;  1 == Master/Proxy */
 BYTE UseRTS  : 1; /* 0 == Don't use RTS line;  1 == Use RTS line */
 BYTE Reserved : 2;    /* Reserved locations */
#endif
 BYTE PreTransmitDelay; /* If UseRTS == 1 delay this many ms (times 2)
before starting transmit */
 BYTE PostTransmitDelay;  /* If UseRTS == 1 delay this many ms (times 2)
after ending transmit */
 BYTE  Unused;  /* Unused byte (set to zero) */
 } SerialSetup;
/* Flags for IPSetup */
#define IPF_USE_BRAM_SETUP 0x00000001
#define IPF_USE_ZERO_BCAST 0x00000002
#define IPF_ENABLE_DHCP  0x00000004
#define IPF_USE_DNS   0x00000008
#define IPF_USE_WINS   0x00000010
typedef struct
 {
 DWORD  Flags;    /* Flags see IPF_XXX above */
 BYTE  Gateway[16];  /* Gateway address   */
 BYTE  IPAddress[16];  /* IP Address     */
 BYTE  Subnet[16];   /* Subnet address    */
 BYTE  DNSAddr[16];  /* Primary DNS (used if IPF_USE_DNS flag is set) */
 BYTE  WINSAddr[16];  /* Primary WINS (used if IPF_USE_WINS flag is set) */
 BYTE  Unused[172];  /* Unused (clear to zero)         */
 } IPSetup;

typedef struct
 {
 WORD Mode;     /* Mode for ErrorLightSetup see ELS_XXXX below   */
 WORD InitVal;    /* Initial value used for ELS_SET and ELS_CYCLE   */
 WORD OnTime;    /* OnTime used for ELS_CYCLE         */
 WORD OffTime;    /* OffTime used for ELS_CYCLE         */
 WORD Num;     /* Number of times to loop for ELS_CYCLE     */
 WORD Val1;     /* Unused value             */
 WORD Val2;     /* Unused value             */
 WORD Val3;     /* Unused value             */
 } ErrorLightSetup;

#define ELS_OFF  0  /* Turns the error light off         */
#define ELS_SET  1  /* Sets the error light to the value of InitVal   */
#define ELS_CYCLE  2  /* Cycles error light.  Begins with value of InitVal
*/
         /* When light is turned on, it stays on for OnTime  */
         /* When light is turned off, it stays off for OffTime */
         /* Cycles lights Num times          */
typedef struct
 {
 BYTE MajorVersion;
 BYTE MinorVersion;
 WORD BuildVersion;
 } VersionDef;

typedef struct
 {
 BYTE SizeofVersionInfo;
 VersionDef BootVersion;
 VersionDef OSVersion;
 BYTE NumOSExtensions;
 VersionDef OSExt[10];
 } VersionInfoDef;

/* Module type defines */
#define MT_EBC   0   /* Ethernet base controller   */
#define MT_ECOM  1   /* Ethernet communications module */
#define MT_WPLC  2   /* WinPLC         */
#define MT_DRIVE  3   /* Drive card        */
#define MT_ERMA  4   /* Ethernet remote master    */
#define MT_CTRIO  5   /* Counter I/O card      */
#define MT_AVG_DISP 6   /* AVG Display Adapter card   */
#define MT_PBC   7   /* Profibus controller     */
#define MT_PBCC  8   /* Profibus IO coprocessor    */
#define MT_UNK   0xFF
/* Module Family defines for MT_EBC, MT_ECOM, MT_WPLC, MT_ERMA */
#define MF_005    0
#define MF_205    2
#define MF_305    3
#define MF_405    4
#define MF_TERM   10
/* Module Family defines for MT_DRIVE */
#define MF_100_SERIES 1  /* Hitachi L100 and SJ100 drives */
#define MF_J300   2  /* Hitachi J300 drive */
#define MF_300_SERIES 3  /* Hitachi SJ300 drive */
#define MF_GS    4  /* GS Series drives  GS-EDRV*/
/* Module Family defines for MT_AVG_DISP */
#define MF_EZ_TOUCH  1  /* AVG EZ-Touch Ethernet adapter */
typedef struct
 {
 BYTE PLCFamily;  /* See MF_XXX defines above */
 BYTE Unused1;
 BYTE ModuleType;  /* See MT_XXX defines above */
 BYTE StatusCode;
 BYTE EthernetAddress[6]; /* Hardware ethernet address */
 WORD RamSize;      /* In K-Byte increments */
 WORD FlashSize;    /* In K-Byte increments */
 BYTE DIPSettings;   /* Settings of the 8 dip switches. */
 BYTE MediaType;    /* 0 == 10-Base T */
        /* 1 == 10-Base F */
 DWORD EPFCount;    /* Early power fail count (405 EBC)*/
#if defined (ANSI_C)
 BYTE  Status;
#else
 BYTE RunRelay : 1;  /* 405 EBC Run Relay Status */
 BYTE BattLow : 1;   /* 405 EBC Battery Low indicator */
 BYTE UnusedBits : 6;  /* Unused status bits */
#endif
 WORD BattRamSize;   /* Size in K-Bytes of battery-backed ram */
 BYTE ExtraDIPS;   /* Extra Dip switches on Terminator EBC's */
 BYTE ModelNumber;
 BYTE EtherSpeed;   /* 0=10MBit; 1=100MBit */
 BYTE PLDRev[2];
 BYTE Unused[14];
 } DeviceDef;
typedef struct
 {
 DWORD Timeout;  /* Timeout 0 == Don't use link monitor */
 BYTE Mode;   /* Mode: */
       /*   0 == Clear outputs */
       /*   1 == Set outputs to given I/O data pattern */
 BYTE Data[251]; /* Pattern:  Used with set outputs,  same format */
       /*     as data for HEIWriteIO call. */
 } LinkMonitor;
typedef struct
 {
 BYTE Algorithm;   /* Algorithm to use for encryption */
       /*  0 == No encryption */
       /*  1 == Private key encryption */
       /* */
 BYTE Unused[3];  /* Reserved for later */
 BYTE Key[60];  /* Encryption key (null terminated) */
 }  Encryption;

typedef struct
 {
 WORD Type;   /* Type of memory */
 DWORD Size;   /* Size of memory */
 DWORD UnitSize; /* 0 = DWORD, 1 = BYTE, 2 = WORD, 4 = DWORD */
 DWORD Unused[3]; /* Unused */
 } MemoryTypeDef;

typedef struct
 {
 WORD SizeofSettings  ;    /* sizeof(HEISettings) */

 /* Action items. */
 DWORD Flags;              /* Flags used to control things. */
             /* Bit:    Function:                    */
             /*  0-31   Unused                    */

 /* RXWX Config items. */
 WORD RXWXACKTimeout    ;   /* Timeout for receiving ACK / NAK */
 WORD RXWXResponseTimeout  ;   /* Timeout for receiving response. */
 WORD RXWXMaxRetrys   ;   /* Number of times to retry a transaction. */

 /* RXWX Stat Items. */
 WORD RXWXMaxACKTime   ;   /* STAT: Max number of ms we have waited for an
ack. */
 WORD RXWXMaxRSPTime   ;   /* STAT: Max number of ms we have waited for a
response. */
 DWORD RXWXACKRetrys   ;       /* STAT: Number of retrys for an ack. */
 DWORD RXWXRSPRetrys   ;   /* STAT: Number of retrys for a response. */
 DWORD RXWXCompleted   ;   /* STAT: Number of successfully completed
transactions */
 DWORD RXWXTimeouts   ;   /* STAT: Number of timeouts on transactions (after
retrys) */
 DWORD RXWXOverruns   ;   /* STAT: Number of times the PLC requested a
transaction while */
             /* one was being processed. */
 DWORD RXWXErrors    ;   /* STAT: Number of times an invalid code was found
or a transaction */
             /* was NAKed. */

 /* Other stuff */
 BYTE Version;        /* Version of this structure.  Currently 0 */

 /* K-Sequence Retrys */
 WORD KSeqMaxRetrys;      /* Max number of times to retry a K-Sequence
request  */
 WORD KSeqRetrys;       /* STAT: Number of K-Sequence retrys.        */
 WORD KSeqTimeouts;      /* STAT: Number of K-Sequence timeouts. */

 BYTE Unused[81];       /* Reserved for future use.  (Configure protocol,
etc. */
 } HEISettings;

typedef struct
 {
 BYTE RunRelayMode;  /* Relay Mode */
         /* See Relay modes below. */
 DWORD SerialTimeout;  /* Used for RRM_DRIVE_COMM_BAD */
 DWORD EthernetTimeout; /* Used for RRM_DRIVE_COMM_BAD */
 BYTE Unused[55];
 } ModuleSetup;

typedef struct
 {
 /*
 ** GS Series drive setup timeouts.
 ** In order for a value to be used, set the most significant bit.
 */
 WORD ReceiveCharTimeout[4];
 WORD CommandResponseTimeout[4];
 WORD WriteCacheClearTime;   /* 250 ms default */
 WORD TimeoutsBeforeAutoBaud;  /*  50 ms default */
 WORD RTSPreTransmitDelay;   /*   4 ms default */
 WORD RTSPostTransmitDelay;   /*   4 ms default */
 WORD AutoBaudDelay;     /*  10 ms default */
 WORD ProcessSlaveIdle;    /*  10 ms default */
 WORD RetryDelay;      /*  20 ms default */
 WORD Unused[49];
 } DriveSetup;

/* Relay Modes */
#define RRM_LINK_GOOD  0 /* Run relay on when link is good (default) */
#define RRM_LINK_NOT_GOOD 1 /* Run relay on when link is not good */
#define RRM_POWERUP_ON  2 /* EBC turns run relay mode on on powerup   */
#define RRM_MANUAL_ON  3 /* Run relay mode is controlled by control software
*/
#define RRM_DRIVE_COMM_BAD 4 /* Relay on if serial or ethernet comm lost
(for Drive controller card) */

#define ACCESS_READ  0
#define ACCESS_WRITE 1
typedef struct sMemRefDetail
 {
 BYTE Direction; /* ACCESS_READ == Read, ACCESS_WRITE == Write */
 WORD Type;   /* Memory type */
 DWORD Offset;  /* Memory Offset */
 WORD NumBytes;  /* Number of bytes */
 } MemRefDetail;
typedef struct
 {
 MemRefDetail Detail;
 BYTE *pBuffer;  /* Data buffer */
 } MemRef;
/* RescanFlags */
#define RESCAN_LEAVE_IMAGE_RAM 0  /* Don't clear the image RAM */
#define RESCAN_CLEAR_IMAGE_RAM 1  /* Clear the image RAM */
/* Protocol Defines */
#define HEIP_HOST     1
#define HEIP_IPX     2
#define HEIP_IP   3
#define HEIP_SERIAL  4

#if !defined(FIRMWARE)
#if defined(HEIDEFS)
typedef int  BOOL;
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
#define FALSE 0
#define TRUE 1
#endif /* #if defined(HEIDEFS) */
#define HEIAPIVERSION 3
#define HEIAPIVERSIONSTRING "3"
#define HEIT_HOST   1
#define HEIT_IPX   2
#define HEIT_WINSOCK  4
#define HEIT_OTHER_TRANSPORT 8
#define HEIT_UNIX   16
#define HEIT_SERIAL  32
/* Encryption Algorithms */
#define HEIEN_NONE   0
#define HEIEN_A1   1
#define PACKET_HEADER_SIZE 9
#if defined(HEIDOS)
#define __declspec(dllexport)
#endif /* #if defined(HEIDOS) */
#if defined(HEI16)
#define __declspec(dllexport)
#endif /* #if defined(HEI16) */
#if defined(HEIUNIX)
#define __declspec(dllexport)
#endif /* #if defined(HEIT_UNIX) */

/* Default values for HEIOpenDevice */
#define DefDevTimeout 100
#define DefDevRetrys  3
#define DefDevUseAddressedBroadcast FALSE

typedef struct
 {
 union
  {
  /* Use this for HEIP_HOST protocol addressing. */
  struct
   {
   short Family;   /* AF_UNSPEC == 0 */
   char Nodenum[6];  /* Ethernet network address */
   unsigned short LANNum; /* Lana number */
   } AddressHost;
  /* Use this for HEIP_IPX protocol addressing. */
  struct
   {
   short Family;   /* AF_IPX == 6 */
   char Netnum[4];   /* Network number */
   char Nodenum[6];  /* Ethernet network address */
   unsigned short Socket; /* Socket number == 0x7070 */
   } AddressIPX;
  /* Use this for HEIP_IP protocol addressing. */
  struct
   {
   short Family;   /* AF_INET == 2 */
   unsigned short Port; /* Port number == 0x7070 */
   union     /* Internet address */
    {
    struct { unsigned char b1,b2,b3,b4; } bAddr;/* Byte addressing */
    struct { unsigned short w1,w2; } wAddr;  /* Word addressing */
    unsigned long lAddr;      /* DWord addressing */
    } AddressingType;
   char  Zero[8];   /* Initialize to zeros */
   } AddressIP;
  /* This is the generic address buffer. */
  BYTE Raw[20];
#ifdef ANSI_C /*  ANSI C cannot have anonymous structures */
  } Address;
#else
  };
#endif
 } ENetAddress;

#if defined(__cplusplus)
extern "C"
 {
#endif /* #if defined(__cplusplus) */
 /* INITIALIZATION / SHUTDOWN */
 __declspec(dllexport) int HEIOpen(WORD HEIAPIVersion);
 __declspec(dllexport) int HEIClose();

 /* Protocol Stuff */
 typedef struct
  {
  WORD Transport;  /* HEIT_HOST */
       /* HEIT_IPX */
       /* HEIT_NETBIOS */
       /* HEIT_WINSOCK */
  WORD Protocol;  /* HEIP_HOST*/
       /* HEIP_IPX */
       /* HEIP_IP */
       /* HEIP_NETBIOS */
  /* Encryption stuff. */
  Encryption Encrypt; /* Set this up before calling HEIOpenTransport  */
       /* .Algorithm == HEIEN_NONE OR HEIEN_A1 */
       /* .Key == Encryption key */

  /* DWORD NetworkAddress; */
  ENetAddress *pSourceAddress; /* Used for multiple ethernet cards.  This
address is the address of the card to use. */
  /*int (*pSendPacket)(HEIDevice *pDevice, BYTE *pPacket, WORD
PacketSize);*/
  /*int (*pReceivePacket)(HEIDevice *pDevice, BYTE *pResponse, int
*pResponseSize);*/
#if HEIAPIVERSION==3
  BYTE Reserved[48];  /* Reserved bytes, set to zero */
#endif
  } HEITransport;

 __declspec(dllexport) int HEIOpenTransport(HEITransport *pTransport, WORD
Version,  ENetAddress *pSourceAddress);
 /* __declspec(dllexport) int HEIOpenTransport(HEITransport *pTransport,
WORD Version, DWORD NetworkAddress );*/
 /* __declspec(dllexport) int HEIOpenTransport(HEITransport *pTransport,
WORD Version, DWORD NetworkAddress = 0); */
 __declspec(dllexport) int HEICloseTransport(HEITransport *pTransport);


 /* DEVICE Stuff */
 typedef struct
  {
  union
   {
   /* Use this for HEIP_HOST protocol addressing. */
   struct
    {
    short Family;   /* AF_UNSPEC == 0 */
    char Nodenum[6];  /* Ethernet network address */
    unsigned short LANNum; /* Lana number */
    } AddressHost;
   /* Use this for HEIP_IPX protocol addressing. */
   struct
    {
    short Family;   /* AF_IPX == 6 */
    char Netnum[4];   /* Network number */
    char Nodenum[6];  /* Ethernet network address */
    unsigned short Socket; /* Socket number == 0x7070 */
    } AddressIPX;
   /* Use this for HEIP_IP protocol addressing. */
   struct
    {
    short Family;   /* AF_INET == 2 */
    unsigned short Port; /* Port number == 0x7070 */
    union     /* Internet address */
     {
     struct { unsigned char b1,b2,b3,b4; } bAddr;/* Byte addressing */
     struct { unsigned short w1,w2; } wAddr;  /* Word addressing */
     unsigned long lAddr;      /* DWord addressing */
     } AddressingType;
    char  Zero[8];   /* Initialize to zeros */
    } AddressIP;
   struct
    {
    BYTE CommPort;
    BYTE ByteSize;
    BYTE Parity;
    BYTE StopBits;
    DWORD Baud;
    void *hLocal;
    } AddressSerial;
   /* This is the generic address buffer. */
   BYTE Raw[20];
   } Address;
  WORD wParam;    /* Application can use this. */
  DWORD dwParam;    /* Application can use this. */
  WORD Timeout;    /* Timeout value in ms (can be changed without closing
the device). */
  WORD Retrys;    /* Number of times to retry (can be changed without
closing the device). */
  BYTE ENetAddress[6];  /* The ethernet address is placed here in the
HEIQueryDevices call. */
  WORD RetryCount;   /* Number of retrys which have occured. */
  WORD BadCRCCount;    /* Number of packets received with bad CRC */
  WORD LatePacketCount;   /* Number of packets received, but after a timeout
*/
  BOOL ParallelPackets;  /* Setting this to TRUE (after HEIOpenDevice) will
enable an application */
         /* to send multiple HEIReadIO, HEIWriteIO, HEICCMRequest or
HEIKSEQRequest requests  */
         /* (to different) modules before waiting for any responses.   */
         /* The application will then need to implement its own retry /
timeout mechanism  */
         /* while waiting for the responses. */
         /* The application uses HEIGetResponse to see if a response for a
module has arrived. */
         /* NOTE: The application should not send multiple requests to a
single module */
         /*       without waiting for the response in between. */
  /* Internal - Do not touch!! */
  BOOL UseAddressedBroadcast; /* Need to close the device and reopen it to
change this! */
  BOOL UseBroadcast;
  DWORD _dwParam;
  WORD DataOffset;
  HEITransport *_pTransport; /* Need to close the device and reopen it to
change this! */
  int SizeOfData;
  BYTE *pData;
  void *pBuffer;
  unsigned short LastAppVal;
#if HEIAPIVERSION==3
  BYTE UseProxy;
  BYTE ProxyBase;
  BYTE ProxySlot;
  BYTE ProxyDevNum;
  BYTE Reserved[44];  /* Reserved bytes, set to zero */
#endif
  } HEIDevice;

 __declspec(dllexport) int HEIQueryDevices(HEITransport *pTransport,
HEIDevice *pDevices, WORD *pNumDevices, WORD HEIAPIVersion);

 __declspec(dllexport) int HEIOpenDevice(HEITransport *pTransport, HEIDevice
*pDevice, WORD HEIAPIVersion, WORD Timeout, WORD Retrys, BOOL
UseAddressedBroadcast);
 /* __declspec(dllexport) int HEIOpenDevice(HEITransport *pTransport,
HEIDevice *pDevice, WORD HEIAPIVersion, WORD Timeout=DefDevTimeout, WORD
Retrys=DefDevRetrys, BOOL
UseAddressedBroadcast=DefDevUseAddressedBroadcast); */
 __declspec(dllexport) int HEICloseDevice(HEIDevice *pDevice);

 __declspec(dllexport) int HEIQueryDeviceData(HEITransport *pTransport,
HEIDevice *pDevices, WORD *pNumDevices, WORD HEIAPIVersion, WORD DataType,
BYTE *pData, WORD SizeofData);

 /* SUPPORT INFORMATION */
 __declspec(dllexport) int HEIReadSupportInfo(HEIDevice *pDevice, BYTE
*pSupportInfo, WORD SizeOfSupportInfo);


 /* VERSION INFORMATION */
 __declspec(dllexport) int HEIReadVersionInfo(HEIDevice *pDevice, BYTE
*pVerInfo, WORD SizeVerInfo);


 /* BASE DEFINITION */
 __declspec(dllexport) int HEIReadBaseDef(HEIDevice *pDevice, BYTE
*pBaseDefInfo, WORD *pSizeOfBaseDefInfo);
 __declspec(dllexport) int HEIWriteBaseDef(HEIDevice *pDevice, BYTE
*pInputBaseDef, WORD SizeOfInputBaseDef, BYTE *pOutputBaseDef, WORD
*pSizeOfOutputBaseDef);
 __declspec(dllexport) int HEIInitBaseDef(HEIDevice *pDevice, BYTE
*pBaseDefInfo, WORD *pSizeOfBaseDefInfo);
 __declspec(dllexport) int HEIRescanBase(HEIDevice *pDevice, DWORD
RescanFlags, BYTE *pBaseDefInfo, WORD *pSizeOfBaseDefInfo);


 /* DEVICE DEFINITION */
 __declspec(dllexport) int HEIReadDeviceDef(HEIDevice *pDevice, BYTE
*pModuleDefInfo, WORD SizeOfModuleDefInfo);
 /* IO ACCESS */
 __declspec(dllexport) int HEIReadIO(HEIDevice *pDevice, BYTE *pData, WORD
*DataSize);
 __declspec(dllexport) int HEIWriteIO(HEIDevice *pDevice, BYTE *pData, WORD
SizeofData, BYTE *pReturnData, WORD *pSizeofReturnData);
 __declspec(dllexport) int HEIWriteIONoRead(HEIDevice *pDevice, BYTE *pData,
WORD SizeofData);
 __declspec(dllexport) int HEIReadIOEx(HEIDevice *apDevice[], BYTE
*apData[], WORD aSizeofData[], int aErrorCode[], int DeviceCount);
 __declspec(dllexport) int HEIWriteIOEx(HEIDevice *apDevice[], BYTE
*apData[], WORD aSizeofData[], BYTE *apReturnData[], WORD
aSizeofReturnData[], int aErrorCode[], int DeviceCount);
 /* CONFIG */
 __declspec(dllexport) int HEIReadConfigData(HEIDevice *pDevice, BYTE
*pData, WORD *DataSize);
 __declspec(dllexport) int HEIWriteConfigData(HEIDevice *pDevice, BYTE
*pData, WORD SizeofData, BYTE *pReturnData, WORD *pSizeofReturnData);
 // NOTE: You can also Use HEIWriteIO to write config data using type
DF_CONFIG

 /* SETUP */
 __declspec(dllexport) int HEIReadSetupData(HEIDevice *pDevice, WORD
SetupType, BYTE *pData, WORD *pSizeofData);
 __declspec(dllexport) int HEIWriteSetupData(HEIDevice *pDevice, WORD
SetupType, BYTE *pData, WORD SizeofData);
 __declspec(dllexport) int HEIDeleteSetupData(HEIDevice *pDevice, WORD
SetupType);
 __declspec(dllexport) int HEIEnumSetupData(HEIDevice *pDevice, WORD *pData,
WORD *pSizeofDataInWords);
 /* WATCHDOG */
 __declspec(dllexport) int HEIPetDevice(HEIDevice *pDevice);
 /* STATISTICS */
 __declspec(dllexport) int HEIReadEthernetStats(HEIDevice *pDevice, BYTE
*pData, WORD *DataSize, BOOL Clear);
 /* __declspec(dllexport) int HEIReadEthernetStats(HEIDevice *pDevice, BYTE
*pData, WORD *DataSize, BOOL Clear=FALSE); */
 /* MODULES STATUS */
 __declspec(dllexport) int HEIReadModuleStatus(HEIDevice *pDevice, BYTE
*pData, WORD *DataSize, BOOL Reset);
 /* __declspec(dllexport) int HEIReadModuleStatus(HEIDevice *pDevice, BYTE
*pData, WORD *DataSize, BOOL Reset=FALSE); */
 /* Multiple Packet Stuff. */
 __declspec(dllexport) int HEIGetResponse(HEIDevice *pDevice, BYTE
*pResponse, int *pResponseSize, BOOL CheckAppVal);
 /* __declspec(dllexport) int HEIGetResponse(HEIDevice *pDevice, BYTE
*pResponse, int *pResponseSize, BOOL CheckAppVal=TRUE); */
   /* ECOM STUFF */
 __declspec(dllexport) int HEICCMRequest(HEIDevice *pDevice, BOOL bWrite,
BYTE DataType, WORD Address, WORD DataLen, BYTE *pData);
 __declspec(dllexport) int HEIKSEQRequest(HEIDevice *pDevice, WORD
DataLenIn, BYTE *pData, WORD *pDataLen);
 /* SERIAL PORT STUFF */
 __declspec(dllexport) int HEIWriteComm(HEIDevice *pDevice, WORD Num2Write,
BYTE *pData);
 __declspec(dllexport) int HEIReadComm(HEIDevice *pDevice, WORD *pNum2Read,
BYTE *pData);
 __declspec(dllexport) int HEIGetRXAvailable(HEIDevice *pDevice, WORD
*pAvailable);
 __declspec(dllexport) int HEIFlushRXQueue(HEIDevice *pDevice);
 __declspec(dllexport) int HEIGetTXLeft(HEIDevice *pDevice, WORD *pLeft);
 __declspec(dllexport) int HEISetupSerialPort(HEIDevice *pDevice,
SerialSetup *pSetup, BOOL WriteToFlash);
 __declspec(dllexport) int HEIReadSerialPortSetup(HEIDevice *pDevice,
SerialSetup *pSetup);

 /* SERIAL PORT STUFF (EX) */
 __declspec(dllexport) int HEIWriteCommEx(HEIDevice *pDevice,BYTE Port ,WORD
Num2Write, BYTE *pData);
 __declspec(dllexport) int HEIReadCommEx(HEIDevice *pDevice, BYTE Port, WORD
*pNum2Read, BYTE *pData);
 __declspec(dllexport) int HEIGetRXAvailableEx(HEIDevice *pDevice, BYTE
Port, WORD *pAvailable);
 __declspec(dllexport) int HEIFlushRXQueueEx(HEIDevice *pDevice, BYTE Port);
 __declspec(dllexport) int HEIFlushTXQueueEx(HEIDevice *pDevice, BYTE Port);
 __declspec(dllexport) int HEIGetTXLeftEx(HEIDevice *pDevice, BYTE Port,
WORD *pLeft);
 __declspec(dllexport) int HEISetupSerialPortEx(HEIDevice *pDevice, BYTE
Port, SerialSetup *pSetup, BOOL WriteToFlash);
 __declspec(dllexport) int HEIReadSerialPortSetupEx(HEIDevice *pDevice, BYTE
Port, SerialSetup *pSetup);
 __declspec(dllexport) int HEIAccessComm(HEIDevice *pDevice, WORD
SendDataSize, BYTE *pSendData, WORD *pReturnDataSize, BYTE *pReturnData);

 /* MEMORY STUFF (see below for types) */
 __declspec(dllexport) int HEIReadMemory(HEIDevice *pDevice, WORD Type,
DWORD Offset, WORD NumBytes, BYTE *pBuffer);
 __declspec(dllexport) int HEIWriteMemory(HEIDevice *pDevice, WORD Type,
DWORD Offset, WORD NumBytes, BYTE *pBuffer);
 __declspec(dllexport) int HEIENumMemory(HEIDevice *pDevice, WORD
*pNumWords, MemoryTypeDef *pBuffer);
 __declspec(dllexport) int HEIAccessMemory(HEIDevice *pDevice, MemRef
MemRefs[], WORD NumRefs);

 /* SHARED RAM STUFF (for Intelligent modules) */
 __declspec(dllexport) int HEIReadSharedRAM(HEIDevice *pDevice, WORD Base,
WORD Slot, WORD Address, WORD Bytes2Read, BYTE *pBuffer);
 __declspec(dllexport) int HEIWriteSharedRAM(HEIDevice *pDevice, WORD Base,
WORD Slot, WORD Address, WORD Bytes2Write, BYTE *pBuffer);

 /* WinPLC specific functions */
#ifndef WINPLC
 __declspec(dllexport) int WPLCSetOSLoad(HEIDevice *pDevice, int Val);
 __declspec(dllexport) int WPLCReboot(HEIDevice *pDevice);
 __declspec(dllexport) int WPLCRunProgram(HEIDevice *pDevice, BYTE
*pProgram);
 __declspec(dllexport) int HEIWriteERMData(HEIDevice *pDevice, WORD Base,
WORD Slot, BYTE DataType, BYTE *pData, WORD NumBytes, WORD Offset);
 __declspec(dllexport) int HEIReadERMData(HEIDevice *pDevice, WORD Base,
WORD Slot, BYTE DataType, BYTE *pData, WORD NumBytes, WORD Offset);
 __declspec(dllexport) int HEIDoERMCommand(HEIDevice *pDevice, WORD Base,
WORD Slot, WORD Command);
 __declspec(dllexport) int HEIDoERMCommandEx(HEIDevice *pDevice, WORD Base,
WORD Slot, WORD Command, BYTE *pExtra, WORD ExtraLen);
 __declspec(dllexport) int WPLCWriteERMData(HEIDevice *pDevice, WORD Base,
WORD Slot, BYTE DataType, BYTE *pData, WORD NumBytes, WORD Offset);
 __declspec(dllexport) int WPLCReadERMData(HEIDevice *pDevice, WORD Base,
WORD Slot, BYTE DataType, BYTE *pData, WORD NumBytes, WORD Offset);
 __declspec(dllexport) int WPLCDoERMCommand(HEIDevice *pDevice, WORD Base,
WORD Slot, WORD Command);
 __declspec(dllexport) int WPLCDoERMCommandEx(HEIDevice *pDevice, WORD Base,
WORD Slot, WORD Command, BYTE *pExtra, WORD ExtraLen);
#endif
 /*
 ** Query timeout function
 */
 /* Sets new query timeout value and returns the old query timeout value */
 __declspec(dllexport) DWORD HEISetQueryTimeout(DWORD NewTimeout);
 /* Gets current query timeout value */
 __declspec(dllexport) DWORD HEIGetQueryTimeout();
 /*
 ** Async Handler for handling extra packets.
 */
 __declspec(dllexport) int HEISetAsyncHandler(void (*pFun)(HEIDevice
*pDevice, BYTE *pResponse, int ResponseLen));
 __declspec(dllexport) int HEIGetAsyncHandler(void (**pFun)(HEIDevice
*pDevice, BYTE *pResponse, int ResponseLen));
/*
** EZ-Ethernet defs
*/
typedef signed   char    SBIT8;
#define MAX_PGM_DATA_LEN  255   // Max packet sent by AVG.
#define MAX_ERR_MSG_SZ     40   // Forty bytes of error message space.
#define MAC_LEN             6   // Six bytes for MAC address
#define SPARE_BYTES         4   // Four spare bytes for future use.
#ifndef NO_ERROR
#define NO_ERROR     0L
#endif
typedef struct
{
    unsigned char Name[20];
    unsigned char Node_ID[2];
    HEIDevice    *pDevice;
} NODELIST;

/*
** Layout of the control buffer.
*/
typedef struct CntlBuffer
{
    BYTE   TaskCode;               /*  Taskcode byte (future use)*/
 BYTE   PanelLock;              /*  1 - Panel has lock, 0 - not locked*/
 BYTE   AdapterLock;            /*  1 - Adapter has lock, 0 - not locked*/
 BYTE   InStatus;               /*  Incoming status*/
 BYTE   OutStatus;              /*  Outgoing status*/
 SBIT8  Seq;                    /*  Sequence number assigned by panel*/
 BYTE   ErrorOffset;            /*  Offset into error array*/
    BYTE   ItemCnt[2];             /*  Two bytes since read tags can be >
256.*/
 BYTE   ErrMsg[MAX_ERR_MSG_SZ]; /*  40 character string.*/
    BYTE   EcomOffset;             /*  Used for panel to panel
communications.*/
    BYTE   Mac[MAC_LEN];           /*  Stores mac address of responding
device.*/
 BYTE   Spare[SPARE_BYTES];     /*  Future use*/
} CNTL_BUF;
/*
** Layout of the program shared ram frame
*/
typedef struct PgmBuffer
{
    CNTL_BUF   CntlBuf;
 BYTE       PgmData[MAX_PGM_DATA_LEN];

} PGM_BUF;

 /*
 ** EZ-Ethernet functions
 */
 __declspec(dllexport) int HEIWriteEZethernetPgmSpace(HEIDevice *pDevice,
BYTE *pData, WORD SizeofData);
 __declspec(dllexport) BOOL EZSendPacket(HEIDevice *pDevice, PGM_BUF
*pBuffer, BYTE *Error_message, unsigned short int Len);
 __declspec(dllexport) NODELIST *EZGetNodeList(unsigned short int *TotalEZ);
 __declspec(dllexport) int SetCRCMode(int Mode);
 __declspec(dllexport) int SendPacketTwoResponses(HEIDevice *pDevice, BYTE
*pPacket, WORD PacketSize, BYTE *pResponse, int *pResponseSize,
         BOOL WaitForResponse, BOOL ReturnWarnings, WORD Bytes2Verify, BYTE
*pVerifyData,
         WORD ExtraTime, BOOL ProcessTimeout, BOOL CheckAppVal);
#if defined(__cplusplus)
 }
#endif /* #if defined(__cplusplus) */
#endif /* #if !defined(FIRMWARE) */
/* Errors */
#define HEIE_NULL        0 /* No Error */
#define HEIE_FIRST_ERROR     0x8000 /* Number for First Error */
#define HEIE_LAST_ERROR      0xFFFF /* Number for Last Error */
#define HEIE_NOT_IMPLEMENTED    0x8000 /* Function not implemented */
#define HEIE_VER_MISMATCH     0x8001 /* Version passed to function not
correct for library */
#define HEIE_UNSUPPORTED_TRANSPORT   0x8002 /* Supplied transport not
supported */
#define HEIE_INVALID_DEVICE     0x8003 /* Supplied device is not valid */
#define HEIE_BUFFER_TOO_SMALL    0x8004 /* Supplied buffer is too small */
#define HEIE_ZERO_BYTES_RECEIVED   0x8005 /* Zero bytes were returned in the
packet */
#define HEIE_TIMEOUT      0x8006 /* Timeout error */
#define HEIE_UNSUPPORTED_PROTOCOL   0x8007 /* Supplied protocol not
supported */
#define HEIE_IP_ADDR_NOT_INITIALIZED  0x8008 /* The devices IP address has
not be set. NOTE: Need to use */
             /* addressed broadcast to talk to the module (with IP) to setup
*/
             /* the IP address. */
#define HEIE_NULL_TRANSPORT      0x8009 /* No transport specified. */
#define HEIE_IPX_NOT_INSTALLED    0x800A /* IPX Transport not installed. */
#define HEIE_IPX_OPEN_SOCKET     0x800B /* Error opening IPX Socket. */
#define HEIE_NO_PACKET_DRIVER    0x800C /* No packet driver found. */
#define HEIE_CRC_MISMATCH     0x800D /* CRC did not match. */
#define HEIE_ALLOCATION_ERROR    0x800E /* Memory allocation error failed.
*/
#define HEIE_NO_IPX_CACHE     0x800F /* No cache has been allocated for IPX
*/
#define HEIE_INVALID_REQUEST    0x8010 /* Invalid request */
#define HEIE_NO_RESPONSE     0x8011 /* No response was available./ requested
*/
#define HEIE_INVALID_RESPONSE    0x8012 /* Invalid format response was
received. */
#define HEIE_DATA_TOO_LARGE     0x8013 /* Given data is too large */
#define HEIE_LOAD_PROC_ERROR    0x8014  /* Error loading procedures */
#define HEIE_NOT_LOADED      0x8015 /* Attempted command before successfull
OpenTransport */
#define HEIE_ALIGNMENT_ERROR    0x8016 /* Data not aligned on proper
boundary */
#define HEIE_FILE_NOT_OPEN     0x8017    /* File not open */
#define HEIE_LOAD_ERROR      0x8100 /* Mask for WinSock load Error see below
(from HEIOpenTransport) */
#define HEIE_LAST_LOAD_ERROR    0x811F /* Last in the range of WinSock load
Errors */
#define HEIE_IO_ERROR      0x9000 /* Mask for IO Error condition (from
HEIReadModuleStatus, HEIReadIO, or HEIWriteIO) */
#define HEIE_IO_WARNING      0xA000 /* Mask for IO Warning condition (from
HEIReadModuleStatus, HEIReadIO, or HEIWriteIO) */
#define HEIE_IO_INFO       0xC000 /* Mask for IO Info condition (from
HEIReadModuleStatus, HEIReadIO, or HEIWriteIO) */
#define HEIE_ICMP_PKT_FOUND    65
#define HEIE_ARP_PKT_FOUND       66
#define HEIE_TYPE_NOT_HANDLED      67
#define HEIE_LINK_SENSE_TRIGGERED  68
#define HEIE_UNK_IP_PACKET     100
#define HEIE_UNK_ETHERTYPE     101
#define HEIE_UNK_PACKET_TYPE     102
#define HEIE_UNK_802X_PACKET_TYPE  103
#define HEIE_UNK_LLC_TYPE     104
#define HEIE_CRC_DOES_NOT_MATCH   105
#define HEIE_CRC_NO_DATA     106
#define HEIE_ENET_ADDR_REPROGRAMMED  107
#define HEIE_NULL_DATA_POINTER   108
#define HEIE_SIZE_ERROR      109
#define HEIE_NOT_FOUND      110
#define HEIE_INVALID_TYPE     111
#define HEIE_RAM_ALREADY_LOCKED   112
#define HEIE_INVALID_REQUEST_INT   113
#define HEIE_TIMEOUT_ERROR     114
#define HEIE_FLASH_PROGRAM_ERROR   115
#define HEIE_INVALID_OS      116
#define HEIE_INVALID_LOCATION    117
#define HEIE_INVALID_SLOT_NUMBER   118
#define HEIE_INVALID_DATA     119
#define HEIE_MODULE_BUSY     120
#define HEIE_CHANNEL_FAILURE    121
#define HEIE_UNUSED_CHANNELS_EXIST  122
#define HEIE_INVALID_UDP_PORT    123
#define HEIE_SHUTDOWN_OS     124
#define HEIE_NOT_MY_IP_ADDRESS   125
#define HEIE_PROTECTION_ERROR    126
#define HEIE_UNK_TYPE_ERROR    127
#define HEIE_BACKPLANE_INIT_ERROR  128
#define HEIE_UNK_RESPONSE     129
#define HEIE_UNK_RXWX_FORMAT    130
#define HEIE_UNK_ACK       131
#define HEIE_UNK_NAK       132
#define HEIE_RANGE_ERROR     133
#define HEIE_LENGTH_WARNING    134
#define HEIE_INVALID_BASE_NUMBER   135
#define HEIE_INVALID_MODULE_TYPE   136
#define HEIE_INVALID_OFFSET    137
#define HEIE_INVALID_BOOT_VER_FOR_OS 138
#define HEIE_BROKEN_TRANSMITTER   139
#define HEIE_INVALID_ADDRESS    140
#define HEIE_TIMING       141
#define HEIE_CHANNEL_FAILURE_MULTI  142
#define HEIE_SERIAL_SETUP_ERROR   143
#define HEIE_NOT_INITIALIZED    144
#define HEIE_INVALID_MODE     145
#define HEIE_COMM_FAILURE     146
#define HEIE_OPERATION_ABORTED   147
#define HEIE_INVALID_RX_CHAR    148
#define HEIE_REQUEST_NAKED     149
#define HEIE_INVALID_OPERATION   150
#define HEIE_VAL_ALREADY_USED    151
/* define HEIE_MODULE_ERROR     152 */
#define HEIE_MODULE_NOT_RESPONDING  153
#define HEIE_BASE_CHANGED     154 /* I/O Base has changed */
#define HEIE_MODULE_FAILURE    155
#define HEIE_PARITY_ERROR     156
#define HEIE_FRAMING_ERROR     157
#define HEIE_OVER_RUN_ERROR    158
#define HEIE_BUFFER_OVERFLOW    159
#define HEIE_ABORT       160
#define HEIE_BUSY        161
#define HEIE_DRIVE_TRIP      162  /* Drive has tripped */
#define HEIE_COMMAND_PENDING    163

#define HEIE_CHANNELS_UNUSED_0   200
#define HEIE_CHANNELS_UNUSED_1   201
#define HEIE_CHANNELS_UNUSED_2   202
#define HEIE_CHANNELS_UNUSED_3   203
#define HEIE_CHANNELS_UNUSED_4   204
#define HEIE_CHANNELS_UNUSED_5   205
#define HEIE_CHANNELS_UNUSED_6   206
#define HEIE_CHANNELS_UNUSED_7   207
#define HEIE_CHANNELS_UNUSED_8   208
#define HEIE_CHANNELS_UNUSED_9   209
#define HEIE_CHANNELS_UNUSED_10   210
#define HEIE_CHANNELS_UNUSED_11   211
#define HEIE_CHANNELS_UNUSED_12   212
#define HEIE_CHANNELS_UNUSED_13   213
#define HEIE_CHANNELS_UNUSED_14   214
#define HEIE_CHANNELS_UNUSED_15   215
#define HEIE_CHANNELS_UNUSED_16   216

/*  Winsock Load Errors
If OpenTransport for WinSock fails, it will return one of the following
errors:
0x8014 Error getting addresses from WinSock.DLL
0x8100 System was out of memory, executable file was corrupt, or relocations
were invalid.
0x8101 Unused
0x8102 File was not found.
0x8103 Path was not found.
0x8104 Unused
0x8105 Attempt was made to dynamically link to a task, or there was a
sharing or network-protection error.
0x8106 Library required separate data segments for each task.
0x8107  Unused
0x8108 There was insufficient memory to start the application.
0x8109  Unused
0x810A Windows version was incorrect.
0x810B Executable file was invalid. Either it was not a Windows application
or there was an error in the .EXE image.
0x810C Application was designed for a different operating system.
0x810D Application was designed for MS-DOS 4.0.
0x810E Type of executable file was unknown.
0x810F Attempt was made to load a real-mode application (developed for an
earlier version of Windows).
0x8110 Attempt was made to load a second instance of an executable file
containing multiple data segments that were not marked read-only.
0x8111 Unused
0x8112 Unused
0x8113 Attempt was made to load a compressed executable file. The file must
be decompressed before it can be loaded.
0x8114 Dynamic-link library (DLL) file was invalid. One of the DLLs required
to run this application was corrupt.
0x8115 Application requires Microsoft Windows 32-bit extensions.
0x8116-0x811F Unused
*/

/* Warnings */
#define HEIW_FIRST_WARNING     0x2000 /* Number for First Error */
#define HEIW_LAST_WARNING     0x2FFF /* Number for Last Error */
#define HEIW_RETRY       0x2000 /* One or more retrys have occurred. */

/* These are masks for values returned from HEIReadIO and/or HEIWriteIO and
indicate that some  */
/* error/warning/info condition exists for some module in the base (it could
be an I/O  */
/* module or it could be the ethernet module.  The function
HEIReadModuleStatus can then be used  */
/* to retrieve the actual conditions.  Note that more than one of the
conditions can exist at any time. */
#define MASK_DEVICE_ERROR   0x1000
#define MASK_DEVICE_WARNING    0x2000
#define MASK_DEVICE_INFO       0x4000

/* Data Types */
#define DT_IP_ADDRESS    0x0010 /* 4 Byte IP address */
#define DT_NODE_NUMBER    0x0020 /* 4 Byte Node Number */
#define DT_SUBNET_MASK    0x0030 /* 4 Byte Subnet Mask */
#define DT_GATEWAY_ADDRESS   0x0040 /* 4 Byte Gateway Address */
#define DT_ERASE_COUNT    0x0050   /* 4 Byte used internally */
#define DT_SERIAL_SETUP    0x0011 /* 8 Byte Serial Setup (see SerialSetup)*/
#define DT_SET_PARM     0x8011 /* 8 Byte Parm Setup (see PARM_XXXX defines)
*/
#define DT_SETUP_ERROR_LIGHT  0x8012 /* 16 Byte Error Light Setup (see
ErrorLightSetup) */
#define DT_STARTUP_SETTINGS  0x0013 /* 32 Byte Startup settings data (see
StartupSettings above) */
#define DT_TIME_OF_DAY    0x8013 /* SYSTEMTIME structure */
#define DT_TYPE_STRING    0x0033 /* 32 Byte ASCII String for netedit type
identification */
#define DT_ENCRYPT_KEY_FLASH  0x0014 /* 64 Byte key data from FALSH See
Encryption structure */
#define DT_ENCRYPT_KEY_RAM   0x8014 /* 64 Byte key data from RAM - This is
the working copy! */
              /* See Encryption structure */
#define DT_MODULE_SETUP    0x0024 /* 64 Byte data from FLASH. See
ModuleSetup structure */
#define DT_RXWX_SETTINGS   0x0015 /* 128 Bytes settings see HEISettings */
#define DT_SETTINGS     0x0015 /* 128 Bytes settings see HEISettings */
#define DT_DRIVE_SETUP    0x0025 /* 128 Byte DriveSetup structure */
#define DT_NODE_NAME     0x0016 /* 256 Byte Node Name */
#define DT_DESCRIPTION    0x0026 /* 256 Byte Node Description */
#define DT_LINK_MONITOR    0x8006 /* 256 Byte Link monitor setup (Ram Based)
*/
              /* See LinkMonitor structure below */
#define DT_IP_SETUP     0x0036 /* 256 Byte IP Setup structure (see IPSetup)
*/
#define DT_WPLC_SYS_INFO   0x0046 /* 256 Byte WinPLC system info (see
WPLCSystemInformation) */
#define DT_ERM_CONFIG    0x0056 /* 256 Byte ERM Config info (see sERMConfig)
*/
#define DT_ERM_INFO     0x8016 /* 256 Byte ERM Info (see sERMInfo) */
#define DT_DEV_COMMAND    0x8026 /* 32 Byte ERM Command (see sDevCommand) */
#define DT_BASE_DEF     0x0017 /* 512 Byte Base Def (405 HEIWriteBaseDef) */
#define DT_RXWX_NODE_ADDR_1  0x0027 /* 512 Byte node address data for addr
00-31 */
#define DT_RXWX_NODE_ADDR_2  0x0037 /* 512 Byte node address data for addr
32-63 */
#define DT_RXWX_NODE_ADDR_3  0x0047 /* 512 Byte node address data for addr
64-95 */
#define DT_R_W_IO_DEF    0x0057 /* 512 Byte read/write IO def (for Drive
card) (base 0) (see MemoryItemBase) */
#define DT_ERM_DEV_00_03   0x0067 /* 512 Byte ERM device data (Devices
numbers 00 - 03) (See sERMDevice) */
#define DT_ERM_DEV_04_07   0x0077 /* 512 Byte ERM device data (Devices
numbers 04 - 07) (See sERMDevice) */
#define DT_ERM_DEV_08_11   0x0087 /* 512 Byte ERM device data (Devices
numbers 08 - 11) (See sERMDevice) */
#define DT_ERM_DEV_12_15   0x0097 /* 512 Byte ERM device data (Devices
numbers 12 - 15) (See sERMDevice) */
#define DT_RESET      0x8010 /* 4 Byte (32-Bit) reset flag.  (RESET_XXX
values below) */
#define DT_BOOT_OS     0x0023 /* 32 Byte OS Boot data */
#define DT_MODULE_INIT_BASE  0x8057 /* 512 Byte Module Initialization data:
(from I/O Base) */

/* Common functions. */
#define FUN_POLLING      0x00  /* Polling one module */
#define FUN_READ_VER_INFO   0x01  /* Read Version Info from module */
#define FUN_READ_SUPPORT_INFO  0x02  /* Read Support Info from module */
           /* 0x03 UNUSED                         */
#define FUN_READ_DEVICE_INFO  0x04  /* Read Device Info from module */
#define FUN_POLLING_ALL    0x05  /* Polling all bases on the network
(returns ethernet address) */
           /* Used as a broadcast function to locate devices on the network.
*/
#define FUN_WRITE_IO    0x06  /* Write IO data to the base */
#define FUN_READ_IO     0x07  /* Read IO data from Base */
#define FUN_READ_BASE_DEF   0x08  /* Read Base Definition */
#define FUN_QUERY_SETUP_DATA  0x09 /* Query the network for a particular
type of data with a particular value */
#define FUN_ENUM_SETUP_DATA   0x0A /* Enumerate the types of data stored in
a module */
#define FUN_READ_SETUP_DATA   0x0B /* Read a particular type of data from a
module */
#define FUN_WRITE_SETUP_DATA  0x0C /* Write a particular type of data to a
module */
#define FUN_DELETE_SETUP_DATA  0x0D /* Delete a particular type of data from
a module */
#define FUN_READ_ETHERNET_STATS  0x0E /* Read ethernet statistics from the
module. */
#define FUN_WRITE_BASE_DEF   0x0F /* Write Base Definition (305/405 EBC) */
           /* 0x10 UNUSED                         */
           /* 0x11 UNUSED                         */
           /* 0x12 UNUSED                         */
           /* 0x13 UNUSED                         */
#define FUN_PET_LINK    0x14  /* Used to keep the link sense timer from
firing in the absense of ReadIO or WriteIO messages */
#define FUN_ADDRESSED_BROADCAST  0x15 /* Used to broadcast to a particular
ethernet address. Used to setup IP address in a new module. */
#define FUN_DATA_BROADCAST   0x16 /* Used to broadcast to a particular data
type. */
#define FUN_READ_MODULE_STATUS  0x17 /* Read the status bytes from each of
the slots of the module. */
#define FUN_INIT_BASE_DEF   0x18 /* Initialize the base def by re-reading
from the backplane */
#define FUN_CCM_REQUEST    0x19 /* Perform a CCM Request with an ECom Module
*/
#define FUN_KSEQ_REQUEST   0x1A /* Perform a K-Seq Request with an ECom
Module */
#define FUN_BACKPLANE_REQUEST  0x1B /* Perform a backplane request on an
ECom Module */
#define FUN_EXTEND_RESPONSE   0x1C  /* Extends the response packet. */
#define FUN_ACK      0x20 /* Acknowledge */
#define FUN_NAK      0x21 /* Not acknowledge */
#define FUN_RESPONSE    0x22 /* Response */
#define FUN_SERIAL_PORT    0x23 /* Execute serial port function (see below)
*/
#define FUN_WRITE_MEMORY   0x24 /* Write a particular memory type */
#define FUN_READ_MEMORY    0x25 /* Read a particular memory type */
#define FUN_ENUM_MEMORY    0x26 /* Get list of all memory types */
#define FUN_ACCESS_MEMORY   0x27 /* Access (Read/Write) multiple memory
types */
#define FUN_READ_SHARED_RAM   0x28 /* Read shared ram */
#define FUN_WRITE_SHARED_RAM  0x29 /* Write shared ram */
#define FUN_WRITE_IO_NO_READ  0x30 /* Write IO without returned read */
#define FUN_COMM_RESPONSE   0x31 /* Response to PLC generated COMM request
*/
#define FUN_COMM_REQ_ACK   0x32 /* Function from PLC generated COMM request
*/
#define FUN_COMM_NO_REQ_ACK  0x33 /* Function from PLC generated COMM
request */
#define FUN_RUN_PROGRAM    0x34 /* Function to execute a program */
#define FUN_REMOTE_API    0x35 /* Function to execute a function on remote
device */
#define FUN_NOTIFY     0x36 /* Indicates a notification */
#define FUN_COMPLETION    0x37 /* Indicates completion of some activity */
#define FUN_PROXY      0x38 /* Indicates a proxy function request */
#define FUN_QUERY_RESPONSE   0x55 /* This is a response to a query function
*/
#define FUN_USER_CONFIG_PANEL    0x60    /* User specific data for AVG
Panel */
#define FUN_WRITE_CONFIG_DATA  0x61  /* Write Config data to the base */
#define FUN_READ_CONFIG_DATA  0x62  /* Read Config data from Base */
#define FUN_UNSUPPORTED    0x99 /* This function will never be supported by
any device (internal use only) */
#define FUN_SET_OS_LOAD    0xF9 /* Set Load OS Parm. */
#define FUN_REBOOT     0xFA /* Reboot OS   */

/* Serial port functions */
#define SPF_WRITE_COMM    0x01  /* Writes one or more characters to the
serial port */
#define SPF_READ_COMM    0x02  /* Reads zero or more characters from the
serial port */
#define SPF_RX_AVAILABLE   0x03  /* Returns number of characters available
in the input queue */
#define SPF_RX_FLUSH     0x04  /* Flushs the serial port input queue */
#define SPF_SETUP      0x05  /* Setup serial port (see SerialSetup above) */
#define SPF_TX_LEFT     0x06  /* Returns number of characters left in the
output queue */
#define SPF_READ_SETUP    0x07  /* Read Setup serial port (see SerialSetup
above) */
#define SPF_ACCESS_COMM    0x08  /* Used to read / write multiple ports */
#define SPF_TX_FLUSH     0x09  /* Flushs the serial port output queue */
/* Serial port commands for HEIAccessComm */
#define SPC_WRITE_PORT    0x01
#define SPC_READ_PORT    0x02
#define SPC_RX_FLUSH     0x04
#define SPC_TX_FLUSH     0x09
#define SPC_ERROR      0x80
#define SPC_READ_RESPONSE   0x82
#define SPC_DONE      0xFF
/* Reset values */
#define RESET_DRIVE_RELAY   0x01 /* Reset relay on ethernet drive card */
/* Parm values */
#define PARM_RETURN_SYS_ERRORS 0x01

/*
 Memory Types.
 Description of memory types.
 A memory type is a 16 bit value that is divided up as follows:
   FEDCBA9876543210
   PKAAFFFFTTTTUNNN
   ||| |   |   ||
   ||| |   |   ||-- Number: Index number from 0 to 7
   ||| |   |   |
   ||| |   |   |-- Undefined (set to zero)
   ||| |   |
   ||| |   |-- Type: 0000 = General Purpose
   ||| |             0001 = Program
   ||| |             0010 = System
   ||| |             0011 = Timer
   ||| |             0100 = Counter
   ||| |             0101 = Setup
   ||| |             0110 = Input
   ||| |             0111 = Output
   ||| |             1000 = Undefined
   ||| |             1001 = Undefined
   ||| |             1010 = Undefined
   ||| |             1011 = Undefined
   ||| |             1100 = Undefined
   ||| |             1101 = Undefined
   ||| |             1110 = Undefined
   ||| |             1111 = Undefined
   ||| |
   ||| |-- Format: 0000 = Bit
   |||             0001 = Byte
   |||             0010 = Word
   |||             0011 = DWord
   |||             0100 = Float
   |||             0101 = Undefined
   |||             0110 = Undefined
   |||             0111 = Undefined
   |||             1000 = Undefined
   |||             1001 = Undefined
   |||             1010 = Undefined
   |||             1011 = Undefined
   |||             1100 = Undefined
   |||             1101 = Undefined
   |||             1110 = Undefined
   |||             1111 = Undefined
   |||
   |||-- Access:  00 = Read / write
   ||             01 = Read Only
   ||             10 = Write Only
   ||             11 = Undefined
   ||
   ||-- Kind of memory: 0 = Ram;  1 = Flash
   |
   |-- Protection:  1 = Protected;  0 = Not Protected


  Example:
   V-Memory in Koyo boxes (205/405) is General Purpose, WORD format, Read /
Write, RAM.
   this would make the type be: 0000 0010 0000 0000 = 0200h = 512

   CR Memory in Koyo boxes is General Purpose, Bit format, Read / Write,
RAM,
   this would make the type be: 0000 0000 0000 0000 = 0000h = 0

   Scratch Pad Memory in Koyo boxes is System, Byte Format, Read / Write,
RAM.
   this would make the type be: 0000 0001 0010 0000 = 0120h = 288

   SP's in Koyo boxes is System, Bit Format, Read Only, RAM
   this would make the type be: 0001 0000 0010 0000 = 1020h = 4128
*/
#define MT_KOYO_V  0x0200  /* V-Memory */
#define MT_KOYO_C  0x0000  /* C-Memory */
#define MT_KOYO_Z  0x0120  /* Scratch Pad Memory */
#define MT_KOYO_SP 0x1020  /* SP-Memory */
#define MT_DRIVE_FIRST 0x300  /* First memory type for Hitachi Drives */
#define MT_HITACHI_D 0x300   /* Hitachi Drive Memory: Monitoring functions
*/
#define MT_HITACHI_F 0x301   /* Hitachi Drive Memory: Basic Profile
functions */
#define MT_HITACHI_A 0x302   /* Hitachi Drive Memory: Standard functions */
#define MT_HITACHI_B 0x303   /* Hitachi Drive Memory: Fine tuning functions
*/
#define MT_HITACHI_C 0x304   /* Hitachi Drive Memory: Intelligent terminal
functions */
#define MT_HITACHI_H 0x305   /* Hitachi Drive Memory: Sensorless vector
functions */
#define MT_HITACHI_O 0x306   /* Hitachi Drive Memory: Other functions */
#define MT_HITACHI_OP 0x307  /* Hitachi Drive Memory: Option Board */
#define MT_HITACHI_R 0x308   /* Hitachi Drive Memory: Reference codes */
/* The following offsets can only be used with HEIReadMemory (not
HEIAccessMemory) */
#define MT_INFO_OFFSET   0x100  /* Add MT_INFO_OFFSET to above MT_HITACHI_?
types to get MemoryTypeInfo for the given ID */
#define MT_VALID_IDS_OFFSET 0x200  /* Add MT_VALID_IDS_OFFSET to above
MT_HITACHI_? types to get the valid Ids for the given memory type */
#define MT_MEMORY_TYPE_STRING 0x300  /* Add MT_MEMORY_TYPE_STRING to above
MT_HITACHI_? types to get the string name for the memory type (use 128 byte
length) */
#define MT_DRIVE_STRING   0x400  /* Add MT_DRIVE_STRING to any of the
MT_HITACHI_? types to get the string name for the current drive (use 32 byte
length) */
#define MT_VERSION_STRING  0x500  /* Add MT_DRIVE_STRING to any of the
MT_HITACHI_? types to get the version string current drive (use 32 byte
length) */
typedef struct
 {
 DWORD MinVal;   /* Minimum value for this type */
 DWORD MaxVal;   /* Maximum value for this type */
 BYTE Magnitude;  /* Magnitude of type.  See MAG_XXXX values */
 BYTE RunModeEdit; /* If TRUE, this field can be edited in run mode */
 BYTE ReadOnly;  /* If TRUE, this field is read-only */
 BYTE FieldType;  /* Type of memory.  see FIELD_XXXX values */
 BYTE NumBits;   /* If FieldType == FIELD_BIT, this tells the number of bits
*/
 BYTE StartBit;  /* If FieldType == FIELD_BIT, this tells the starting bit
number */
 BYTE  Size;    /* Internal size in bytes */
 WORD  Addr;    /* Internal address */
 BYTE Unused[13];  /* Unused */
 WORD NameLength;  /* Length of pName (including null terminator) */
 char Name[224];  /* Name string for the given memory type */
 } MemoryTypeInfo;

typedef struct
 {
 WORD Type;
 WORD Id;
 } MemoryItem;
typedef struct
 {
 MemoryItem Items[16];
 } MemoryItemSlot;
typedef struct
 {
 MemoryItemSlot Slot[8];
 } MemoryItemBase;
#define FIELD_NORMAL  0
#define FIELD_CODE  1
#define FIELD_BIT   2
#define MAG_00001   0
#define MAG_00010   1
#define MAG_00100   2
#define MAG_01000   3

/* Hitachi Drive type defines */
#define L100 1
#define SJ100 2
#define J300 3
#define SJ300 4
/* GS Drive type defines */
#define GS1  1
#define GS2  2
#define GS3  3
#define GS4  4
/* Defines for Data formats */
#define DF_BIT_IN   0x03
#define DF_BIT_OUT  0x04
#define DF_BYTE_IN  0x10
#define DF_BYTE_OUT  0x11
#define DF_WORD_IN  0x05
#define DF_WORD_OUT  0x06
#define DF_DWORD_IN  0x08
#define DF_DWORD_OUT  0x09
#define DF_DOUBLE_IN  0x12
#define DF_DOUBLE_OUT 0x13
#define DF_FLOAT_IN  0x14
#define DF_FLOAT_OUT  0x15
#define DF_CONFIG   0x16

/* Data type defines for HX-ERM */
#define DATA_SIZE_INFO  0  /* Used to read the size info for     */
#define DATA_INPUT   1  /* Used to read/write all input data    */
#define DATA_OUTPUT   2  /* Used to read/write all output data    */
#define DATA_DESCRIPTION 3  /* Used to read description/layout of I/O
data */
#define DATA_COMMAND   4  /* Used to read/write to command buffer   */
#define DATA_ERMINFO   5  /* Used to read sERMInfo structure     */
/* Commands for the HX-ERM module */
#define COMMAND_PROCESS_IO      1
#define COMMAND_ABORT       2
#define COMMAND_PROCESS_COMMAND_BUFFER  3

/* Restore structure alignment boundary */
#pragma pack()

#endif /* #if !defined(__HEI_H) */


#include "defs.h"
#include <memory.h>
#include <malloc.h>
#include "hei.h"
#define TimeDiff(StartTime, EndTime)  (((DWORD)EndTime > (DWORD)StartTime) ?
((DWORD)EndTime - (DWORD)StartTime) : ((DWORD)EndTime + ((DWORD)ULONG_MAX -
(DWORD)StartTime) + 1))
DWORD HEIIGetCounter();
int GetResponseEx(HEIDevice *apDevice[], BYTE *apData[], WORD aSizeofData[],
int aErrorCode[], int DeviceCount)
 {
 int Done = TRUE;
 int idx = 0;
 for(idx = 0; idx < DeviceCount; idx++)
  {
  /* Handle NULL device */
  if(!apDevice[idx])
   continue;
  if(aErrorCode[idx] == HEIE_NO_RESPONSE)
   {
   BYTE Buff[500];
   int BuffLen = sizeof(Buff);
   aErrorCode[idx] = HEIGetResponse(apDevice[idx], Buff, &BuffLen, TRUE);
   /* If no response, continue */
   if(aErrorCode[idx] == HEIE_NO_RESPONSE)
    {
    Done = FALSE;
    continue;
    }
   /* Check for error and not warning. */
   if(aErrorCode[idx] && !(aErrorCode[idx] & HEIW_FIRST_WARNING))
    {
    /* Set data size to 0 */
    aSizeofData[idx] = 0;
    }
   else
    {
    if(BuffLen)
     {
     short int *pInt = (short int *)&Buff[PACKET_HEADER_SIZE];
     BuffLen -= PACKET_HEADER_SIZE;
     BuffLen -= 2;
     if((WORD)BuffLen > aSizeofData[idx])
      {
      BuffLen = aSizeofData[idx];
      aErrorCode[idx] = HEIE_BUFFER_TOO_SMALL;
      }
     if(*pInt)
      aErrorCode[idx] = (*pInt) | 0x8000;
     memcpy(apData[idx], Buff+PACKET_HEADER_SIZE+2, BuffLen);
     aSizeofData[idx] = BuffLen;
     }
    else
     {
     /* Set data size to 0 */
     aSizeofData[idx] = 0;
     aErrorCode[idx] = HEIE_ZERO_BYTES_RECEIVED;
     }
    }
   }
  }
 return Done;
 }
DWORD StartHEIReadIO(HEIDevice *pDevice, BYTE *pData, WORD *pSizeofData, int
*pErrorCode)
 {
 DWORD StartTime = 0;
 BOOL OldPP = FALSE;
 /* Force parallel packet mode */
 OldPP = pDevice->ParallelPackets;
 pDevice->ParallelPackets = TRUE;
 /* Init error code */
 *pErrorCode = HEIE_NO_RESPONSE;
 /* Log the time */
 StartTime = HEIIGetCounter();
 /* Send request */
 HEIReadIO(pDevice, pData, pSizeofData);
 /* Restore parallel packet mode */
 pDevice->ParallelPackets = OldPP;
 return StartTime;
 }
__declspec(dllexport) int HEIReadIOEx
 (
 HEIDevice *apDevice[],
 BYTE *apData[],
 WORD aSizeofData[],
 int aErrorCode[],
 int DeviceCount
 )
 {
 int idx = 0;
 BOOL Done = FALSE;
 DWORD *pStartTime = (DWORD *)calloc(sizeof(DWORD), DeviceCount);
 int MaxStarted = 0;
 int StartAt = 0;
 /* Reset retry count */
 for(idx = 0; idx < DeviceCount; idx++)
  if(apDevice[idx])
   apDevice[idx]->SizeOfData = 0;
 while(!Done)
  {
  /* Start a request */
  for(idx = StartAt; idx < DeviceCount; idx++)
   {
   /* Handle NULL device */
   if(!apDevice[idx])
    {
    StartAt = idx + 1;
    if(idx+1 > MaxStarted)
     MaxStarted = idx + 1;
    }
   /* If request not started, start it */
   else if(!pStartTime[idx])
    {
    pStartTime[idx] = StartHEIReadIO(apDevice[idx], apData[idx],
&aSizeofData[idx], &aErrorCode[idx]);
    StartAt = idx + 1;
    if(idx+1 > MaxStarted)
     MaxStarted = idx + 1;
    break;
    }
   }
  /* Test for completion of requests */
  GetResponseEx(apDevice, apData, aSizeofData, aErrorCode, MaxStarted);
  /* When all have been started, we're done until proven otherwise */
  Done = MaxStarted == DeviceCount;

  /* Test for timeout of requests */
  for(idx = 0; idx < MaxStarted; idx++)
   {
   /* Handle NULL device */
   if(!apDevice[idx])
    continue;
   /* If request started, test timeout */
   if(aErrorCode[idx] == HEIE_NO_RESPONSE && pStartTime[idx])
    {
    /* Check timeout for device */
    if(TimeDiff(pStartTime[idx], HEIIGetCounter()) >=
apDevice[idx]->Timeout)
     {
     /* Timed out, check retries */
     if(apDevice[idx]->SizeOfData < apDevice[idx]->Retrys)
      {
      apDevice[idx]->SizeOfData++;
      apDevice[idx]->RetryCount++;
      /* Reset */
      pStartTime[idx] = 0;
      aErrorCode[idx] == HEIE_NO_RESPONSE;
      if(idx < StartAt)
       StartAt = idx;

      /* Not done */
      Done = FALSE;
      }
     /* No more retries */
     else
      {
      /* Set error code */
      aErrorCode[idx] = HEIE_TIMEOUT;

      /* This device is done */
      }
     }
    /* Started but not timed out */
    else
     /* Not done */
     Done = FALSE;
    }
   /* If not started... */
   else if(!pStartTime[idx])
    {
    /* Can't be done */
    Done = FALSE;
    }
   }
  }
 free(pStartTime);
 return 0;
 }
DWORD StartHEIWriteIO(HEIDevice *pDevice, BYTE *pData, WORD SizeofData, BYTE
*pReturnData, WORD *pSizeofReturnData, int *pErrorCode)
 {
 DWORD StartTime = 0;
 BOOL OldPP = FALSE;
 /* Force parallel packet mode */
 OldPP = pDevice->ParallelPackets;
 pDevice->ParallelPackets = TRUE;
 /* Init error code */
 *pErrorCode = HEIE_NO_RESPONSE;
 /* Log the time */
 StartTime = HEIIGetCounter();
 /* Send request */
 HEIWriteIO(pDevice, pData, SizeofData, pReturnData, pSizeofReturnData);
 /* Restore parallel packet mode */
 pDevice->ParallelPackets = OldPP;
 return StartTime;
 }
__declspec(dllexport) int HEIWriteIOEx
 (
 HEIDevice *apDevice[],
 BYTE *apData[],
 WORD aSizeofData[],
 BYTE *apReturnData[],
 WORD aSizeofReturnData[],
 int aErrorCode[],
 int DeviceCount
 )
 {
 int idx = 0;
 BOOL Done = FALSE;
 DWORD *pStartTime = (DWORD *)calloc(sizeof(DWORD), DeviceCount);
 int MaxStarted = 0;
 int StartAt = 0;
 /* Reset retry count */
 for(idx = 0; idx < DeviceCount; idx++)
  if(apDevice[idx])
   apDevice[idx]->SizeOfData = 0;
 while(!Done)
  {
  /* Start a request */
  for(idx = StartAt; idx < DeviceCount; idx++)
   {
   /* Handle NULL device */
   if(!apDevice[idx])
    {
    StartAt = idx + 1;
    if(idx+1 > MaxStarted)
     MaxStarted = idx + 1;
    }
   /* If request not started, start it */
   else if(!pStartTime[idx])
    {
    pStartTime[idx] = StartHEIWriteIO(apDevice[idx], apData[idx],
aSizeofData[idx], apReturnData[idx], &aSizeofReturnData[idx],
&aErrorCode[idx]);
    StartAt = idx + 1;
    if(idx+1 > MaxStarted)
     MaxStarted = idx + 1;
    break;
    }
   }
  /* Test for completion of requests */
  GetResponseEx(apDevice, apReturnData, aSizeofReturnData, aErrorCode,
MaxStarted);
  /* When all have been started, we're done until proven otherwise */
  Done = MaxStarted == DeviceCount;

  /* Test for timeout of requests */
  for(idx = 0; idx < MaxStarted; idx++)
   {
   /* Handle NULL device */
   if(!apDevice[idx])
    continue;
   /* If request started, test timeout */
   if(aErrorCode[idx] == HEIE_NO_RESPONSE && pStartTime[idx])
    {
    /* Check timeout for device */
    if(TimeDiff(pStartTime[idx], HEIIGetCounter()) >=
apDevice[idx]->Timeout)
     {
     /* Timed out, check retries */
     if(apDevice[idx]->SizeOfData < apDevice[idx]->Retrys)
      {
      apDevice[idx]->SizeOfData++;
      apDevice[idx]->RetryCount++;
      /* Reset */
      pStartTime[idx] = 0;
      aErrorCode[idx] == HEIE_NO_RESPONSE;
      if(idx < StartAt)
       StartAt = idx;

      /* Not done */
      Done = FALSE;
      }
     /* No more retries */
     else
      {
      /* Set error code */
      aErrorCode[idx] = HEIE_TIMEOUT;

      /* This device is done */
      }
     }
    /* Started but not timed out */
    else
     /* Not done */
     Done = FALSE;
    }
   /* If not started... */
   else if(!pStartTime[idx])
    {
    /* Can't be done */
    Done = FALSE;
    }
   }
  }
 free(pStartTime);
 return 0;
 }

#if 0
int GetResponseEx(HEIDevice *apDevice[], BYTE *apData[], WORD aSizeofData[],
int aErrorCode[], int DeviceCount)
 {
 int Done = TRUE;
 int idx = 0;
 for(idx = 0; idx < DeviceCount; idx++)
  {
  /* Handle NULL device */
  if(!apDevice[idx])
   continue;
  if(aErrorCode[idx] == HEIE_NO_RESPONSE)
   {
   BYTE Buff[500];
   int BuffLen = sizeof(Buff);
   aErrorCode[idx] = HEIGetResponse(apDevice[idx], Buff, &BuffLen, TRUE);
   /* If no response, continue */
   if(aErrorCode[idx] == HEIE_NO_RESPONSE)
    {
    Done = FALSE;
    continue;
    }
   /* Check for error and not warning. */
   if(aErrorCode[idx] && !(aErrorCode[idx] & HEIW_FIRST_WARNING))
    {
    /* Set data size to 0 */
    aSizeofData[idx] = 0;
    }
   else
    {
    if(BuffLen)
     {
     short int *pInt = (short int *)&Buff[PACKET_HEADER_SIZE];
     BuffLen -= PACKET_HEADER_SIZE;
     BuffLen -= 2;
     if((WORD)BuffLen > aSizeofData[idx])
      {
      BuffLen = aSizeofData[idx];
      aErrorCode[idx] = HEIE_BUFFER_TOO_SMALL;
      }
     if(*pInt)
      aErrorCode[idx] = (*pInt) | 0x8000;
     memcpy(apData[idx], Buff+PACKET_HEADER_SIZE+2, BuffLen);
     aSizeofData[idx] = BuffLen;
     }
    else
     {
     /* Set data size to 0 */
     aSizeofData[idx] = 0;
     aErrorCode[idx] = HEIE_ZERO_BYTES_RECEIVED;
     }
    }
   }
  }
 return Done;
 }
__declspec(dllexport) int HEIReadIOEx
 (
 HEIDevice *apDevice[],
 BYTE *apData[],
 WORD aSizeofData[],
 int aErrorCode[],
 int DeviceCount,
 DWORD Timeout
 )
 {
 DWORD StartTime = HEIIGetCounter();
 int idx = 0;
 BOOL Done = FALSE;
 BOOL OldPP = FALSE;
 for(idx = 0; idx < DeviceCount; idx++)
  {
  /* Handle NULL device */
  if(!apDevice[idx])
   continue;
  /* Force parallel packet mode */
  OldPP = apDevice[idx]->ParallelPackets;
  apDevice[idx]->ParallelPackets = TRUE;
  /* Init error code */
  aErrorCode[idx] = HEIE_NO_RESPONSE;
  /* Send request */
  HEIReadIO(apDevice[idx], apData[idx], &aSizeofData[idx]);
  /* Check for response */
  GetResponseEx(apDevice, apData, aSizeofData, aErrorCode, idx+1);
  /* Restore parallel packet mode */
  apDevice[idx]->ParallelPackets = OldPP;
  }
 /* Spin on GetResponseEx waiting for timeout */
 while(!Done)
  {
  Done = GetResponseEx(apDevice, apData, aSizeofData, aErrorCode, idx);
  if(TimeDiff(StartTime, HEIIGetCounter()) >= Timeout)
   return HEIE_TIMEOUT;
  }
 return 0;
 }
__declspec(dllexport) int HEIWriteIOEx
 (
 HEIDevice *apDevice[],
 BYTE *apData[],
 WORD aSizeofData[],
 BYTE *apReturnData[],
 WORD aSizeofReturnData[],
 int aErrorCode[],
 int DeviceCount,
 DWORD Timeout
 )
 {
 DWORD StartTime = HEIIGetCounter();
 int idx = 0;
 BOOL Done = FALSE;
 BOOL OldPP = FALSE;
 for(idx = 0; idx < DeviceCount; idx++)
  {
  /* Handle NULL device */
  if(!apDevice[idx])
   continue;
  /* Force parallel packet mode */
  OldPP = apDevice[idx]->ParallelPackets;
  apDevice[idx]->ParallelPackets = TRUE;
  /* Init error code */
  aErrorCode[idx] = HEIE_NO_RESPONSE;
  /* Send request */
  HEIWriteIO(apDevice[idx], apData[idx], aSizeofData[idx],
apReturnData[idx], &aSizeofReturnData[idx]);
  /* Check for response */
  GetResponseEx(apDevice, apReturnData, aSizeofReturnData, aErrorCode,
idx+1);
  /* Restore parallel packet mode */
  apDevice[idx]->ParallelPackets = OldPP;
  }
 /* Spin on GetResponseEx waiting for timeout */
 while(!Done)
  {
  Done = GetResponseEx(apDevice, apReturnData, aSizeofReturnData,
aErrorCode, idx);
  if(TimeDiff(StartTime, HEIIGetCounter()) >= Timeout)
   return HEIE_TIMEOUT;
  }
 return 0;
 }
#endif

/*
** HEI.C - Platform dependent code for communicating with Host Automation
Products
**   line of ethernet modules using the WinSock transport.
**
** Copyright (C) - 1996-1998 Host Automation Products, Inc.
**
*/
#include "winsock.h"  /* Needed for winsock calls */
#include "wsipx.h"   /* Needed for winsock IPX calls */
#include "mmsystem.h"  /* Needed for timer stuff */
#include "hei.h"
#include <memory.h>
/*
** Notes for porting code to another platform:
**
** This file contains the transport/system dependant code for use with the
** Host Ethernet Interface (HEI).  There are nine functions which must be
** implemented by this code:
**
**  1) int HEIIOpen();
**  2) int HEIIClose();
**  3) int HEIIOpenTransport(HEITransport *pTransport);
**  4) int HEIICloseTransport(HEITransport *pTransport);
**  5) int HEIIOpenDevice(HEITransport *pTransport, HEIDevice *pDevice);
**  6) int HEIICloseDevice(HEIDevice *pDevice);
**  7) int HEIIReceivePacket(HEIDevice *pDevice, BYTE *pResponse, int
*pResponseSize);
**  8) int HEIISendPacket(HEIDevice *pDevice, BYTE *pPacket, WORD
PacketSize);
**  9) DWORD HEIIGetCounter();
**
** Make changes in this file, do not change HEI.C or any structures in
HEI.H!
** If you find that you must change something in HEI.C, contact the person
** you got this source from.
**
** Feel free to remove any of the WinSock specific code from this module.
**
** To compile the code for ANSI C, ANSI_C must be defined!
**
** See all sections containing "TODO_FOR_OTHER_SYSTEM" for further details.
**
*/

/* Counter for the number of times that OpenTransport has been called */
static int WinSockLoadCount = 0;
/*
** Windows version gets stored here.  It is used for setting winsock options

** Win 16 is slightly different than Win 32.
*/
WORD  WinVer=0;
/* This is the port number to use when talking to a module. */
#define PORT_ID 0x7070
/* This function should return a millisecond resolution tick counter. */
DWORD HEIIGetCounter()
 {
 /*return timeGetTime(); */
 LARGE_INTEGER freq, count;
 QueryPerformanceFrequency(&freq);
 QueryPerformanceCounter(&count);
 return (DWORD)((count.QuadPart * 1000) / freq.QuadPart);
 }

/*
** This function is called from within HEIOpen. It gives the opportunity
** to do initialization type stuff.  NOTE: This function may be called more
** than once!
**
** RETURNS:  0 on success
**           non-zero on error.
*/
int HEIIOpen()
 {
 /* Save the windows version for later use. */
 DWORD dwVersion = GetVersion();
 WinVer = LOWORD(dwVersion);
 /*
 ** TODO_FOR_OTHER_SYSTEM
 ** Do system level init stuff here.
 ** Be aware that this may be called more than once.
 */
 return HEIE_NULL;
 }

/*
** This function is called from within HEIClose. It gives the opportunity
** to do shutdown type stuff.  NOTE: This function may be called more
** than once!
**
** RETURNS:  0 on success
**           non-zero on error.
*/
int HEIIClose()
 {
 /*
 ** TODO_FOR_OTHER_SYSTEM
 ** Do system level shut down stuff here.
 ** Be aware that this may be called more than once.
 */
 return HEIE_NULL;
 }

/*
** This function is called from within HEIOpenTransport.  It is used to
prepare
** the given Transport to be used in subsequent HEIOpenDevice calls.
**
** RETURNS:  0 on success
**           non-zero on error.
*/
int HEIIOpenTransport(HEITransport *pTransport)
 {
 switch (pTransport->Transport)
  {
  case HEIT_WINSOCK:   /* Open Transport type HEIT_WINSOCK */
   {
   /* WinSock Transport. Protocol must be either IPX or IP */
   if (pTransport->Protocol == HEIP_IPX || pTransport->Protocol == HEIP_IP)
    {
    /* Keep track of load count, Initialize winsock if zero. */
    if (!WinSockLoadCount)
     {
     WSADATA wsaData;
     WORD wVersionRequested = MAKEWORD(2, 0);

     /* Initialize winsock dll */
     if(WSAStartup(wVersionRequested, &wsaData) == SOCKET_ERROR)
      return WSAGetLastError();
     }
    WinSockLoadCount++;
    }
   else
    return HEIE_UNSUPPORTED_PROTOCOL;
   break;
   }

  case HEIT_OTHER_TRANSPORT:
   {
   /*
   ** TODO_FOR_OTHER_SYSTEM
   ** Do one time init stuff by keeping track of the number of times this
   ** transport has been opened.
   ** Don't return HEIE_UNSUPPORTED_TRANSPORT
   */
   return HEIE_UNSUPPORTED_TRANSPORT;
   }

  default:
   return HEIE_UNSUPPORTED_TRANSPORT;
  }

 return HEIE_NULL;
   }


/*
** This function is called from within HEICloseTransport.  It indicates
** that the given Transport is no longer in use.
**
** RETURNS:  0 on success
**           non-zero on error.
*/
int HEIICloseTransport(HEITransport *pTransport)
 {
 switch (pTransport->Transport)
  {
  case HEIT_WINSOCK:      /* Close Transport type HEIT_WINSOCK */
   {
   /* WinSock Transport. Protocol must be IPX or IP */
   if (pTransport->Protocol == HEIP_IPX || pTransport->Protocol == HEIP_IP)
    {
    /* Decrement load count.  Shut down WinSock if zero */
    if (WinSockLoadCount)
     {
     WinSockLoadCount--;
     if (!WinSockLoadCount)
      WSACleanup();
     }
    }
   else
    return HEIE_UNSUPPORTED_PROTOCOL;

   break;
   }

  case HEIT_OTHER_TRANSPORT:
   {
   /*
   ** TODO_FOR_OTHER_SYSTEM
   ** Decrement load counter, do cleanup stuff if zero.
   ** Don't return HEIE_UNSUPPORTED_TRANSPORT
   */
   return HEIE_UNSUPPORTED_TRANSPORT;
   }

  default:
   return HEIE_UNSUPPORTED_TRANSPORT;
  }

 return HEIE_NULL;
   }


/*
** This function is called from within HEIOpenDevice.  It is used to prepare
** the given Device to be used with the given Transprot.
**
** RETURNS:  0 on success
**           non-zero on error.
*/
int HEIIOpenDevice(HEITransport *pTransport, HEIDevice *pDevice)
 {
 switch (pTransport->Transport)
  {
  case HEIT_WINSOCK:  /* Open Device type HEIT_WINSOCK */
   {
   /* WinSock Transport. */
   SOCKET sock;
   struct sockaddr *pRemAddr, *pMyAddr;
   int SizeRemAddr, SizeMyAddr;
   u_long NonBlockingMode;
   if (pTransport->Protocol == HEIP_IPX)
    {
    static SOCKADDR_IPX RemAddr, MyAddr;
    /* Initialize remote address */
    if (!pDevice->UseBroadcast)
     memcpy(&RemAddr, pDevice->Address.Raw, sizeof(SOCKADDR_IPX));
    if (pTransport->pSourceAddress)
     {
     MyAddr.sa_family = pTransport->pSourceAddress->AddressIPX.Family;
     memcpy(MyAddr.sa_netnum, pTransport->pSourceAddress->AddressIPX.Netnum,
4);
     memcpy(MyAddr.sa_nodenum,
pTransport->pSourceAddress->AddressIPX.Nodenum, 6);
     MyAddr.sa_socket = pTransport->pSourceAddress->AddressIPX.Socket;
     }
    else
     {
     /* Initialize MyAddr to all zeros so that windows can tell me who I am!
*/
     MyAddr.sa_family = AF_IPX;
     /*memcpy(MyAddr.sa_netnum, &pTransport->NetworkAddress, 4);*/
     memset(MyAddr.sa_netnum, 0, 4);
     memset(MyAddr.sa_nodenum, 0, 6);
     MyAddr.sa_socket = 0x00;
     }
    /* get socket handle */
    sock = socket(AF_IPX,        /* IPX family */
         SOCK_DGRAM,    /* Datagram */
         NSPROTO_IPX);
    pRemAddr = (struct sockaddr *) &RemAddr;
    pMyAddr = (struct sockaddr *) &MyAddr;
    SizeRemAddr = sizeof(RemAddr);
    SizeMyAddr = sizeof(MyAddr);
    }
   else if (pTransport->Protocol == HEIP_IP)
    {
    static struct sockaddr_in RemAddr, MyAddr;
    /*
    ** If Protocol is IP and we are not using broadcast, and
    ** Address.Raw[19] == 1 then the IP address in the module
    ** is undefined.
    */
    if (!pDevice->UseBroadcast && (pDevice->Address.Raw[19] == 1))
     return HEIE_IP_ADDR_NOT_INITIALIZED;

    /* Initialize remote address */
    if (!pDevice->UseBroadcast)
     memcpy(&RemAddr, pDevice->Address.Raw, sizeof(RemAddr));
    if (pTransport->pSourceAddress)
     {
     MyAddr.sin_family = pTransport->pSourceAddress->AddressIP.Family;
     MyAddr.sin_port = pTransport->pSourceAddress->AddressIP.Port;
     MyAddr.sin_addr.s_addr =
pTransport->pSourceAddress->AddressIP.AddressingType.lAddr;
     }
    else
     {
     /* Initialize MyAddr to all zeros so that windows can tell me who I am!
*/
     MyAddr.sin_family = AF_INET;
     MyAddr.sin_port = 0;
     MyAddr.sin_addr.s_addr = 0;
     }
    /* get socket handle */
    sock = socket(AF_INET,       /* IP family */
         SOCK_DGRAM,    /* Datagram */
         IPPROTO_UDP);
    pRemAddr = (struct sockaddr *) &RemAddr;
    pMyAddr = (struct sockaddr *) &MyAddr;
    SizeRemAddr = sizeof(RemAddr);
    SizeMyAddr = sizeof(MyAddr);
    }
   else
    return HEIE_UNSUPPORTED_PROTOCOL;

   if(sock == INVALID_SOCKET)
    return WSAGetLastError();
   if (bind (sock, pMyAddr, SizeMyAddr) == SOCKET_ERROR)
    {
    int Error = WSAGetLastError();
    closesocket(sock);
    return Error;
    }
   if (pDevice->UseBroadcast)
    {
    int rSetSockOpt;

    if (WinVer < 0x0332) /* Check for WinVer < 3.50 */
     {
     /* 16 Bit uses int type. */
     int AllowBroadcast = TRUE;
     rSetSockOpt = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char *)
&AllowBroadcast, sizeof(AllowBroadcast));
     }
    else
     {
     /* 32 Bit uses long type. */
     long AllowBroadcast = TRUE;
     rSetSockOpt = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char *)
&AllowBroadcast, sizeof(AllowBroadcast));
     }

    if (rSetSockOpt == SOCKET_ERROR)
     {
     int Error = WSAGetLastError();
     closesocket(sock);
     return Error;
     }
    }
   else
    {
    if (connect (sock, pRemAddr, SizeRemAddr) == SOCKET_ERROR)
     {
     int Error = WSAGetLastError();
     closesocket(sock);
     return Error;
     }
    }
   /* Setup for non-blocking mode */
   NonBlockingMode = 1;
   if (ioctlsocket (sock, FIONBIO, &NonBlockingMode) == SOCKET_ERROR)
    {
    int Error = WSAGetLastError();
    closesocket(sock);
    return Error;
    }

   pDevice->_dwParam = (DWORD) sock;
   break;
   }

  case HEIT_OTHER_TRANSPORT:
   {
   /*
   ** TODO_FOR_OTHER_SYSTEM
   ** Prepare to communicate with the given device.
   ** The address to talk to is stored in pDevice->Address (see HEI.H for
format)
   ** Be aware that pDevice->UseBroadcast indicates that we
   ** will be broadcasting to the module.
   ** For IP, pDevice->Address.Raw[19] == 1 (after a query)
   ** if the given module's IP address is not initialized.  In
   ** this case, the only way to talk to it (using IP) is by
   ** using addressed broadcast.
   ** You can use pDevice->_dwParam to store whatever (such as
   ** a socket number).
   ** Don't return HEIE_UNSUPPORTED_TRANSPORT
   */
   return HEIE_UNSUPPORTED_TRANSPORT;
   }

  default:
   return HEIE_UNSUPPORTED_TRANSPORT;
  }

 return HEIE_NULL;
 }

/*
** This function is called from within HEICloseDevice.  It indicates
** that the given Device is no longer in use.
**
** RETURNS:  0 on success
**           non-zero on error.
*/
int HEIICloseDevice(HEIDevice *pDevice)
 {
 switch (pDevice->_pTransport->Transport)
  {
  case HEIT_WINSOCK:  /* Close Device type HEIT_WINSOCK */
   {
   /* WinSock Transport. */
   if (pDevice->_pTransport->Protocol == HEIP_IPX ||
pDevice->_pTransport->Protocol == HEIP_IP)
    {
    SOCKET sock = (SOCKET) pDevice->_dwParam;

    if (closesocket(sock) == SOCKET_ERROR)
     return WSAGetLastError();
    }
   else
    return HEIE_UNSUPPORTED_PROTOCOL;
   break;
   }

  case HEIT_OTHER_TRANSPORT:
   {
   /*
   ** TODO_FOR_OTHER_SYSTEM
   ** Do device type shutdown stuff.
   ** Don't return HEIE_UNSUPPORTED_TRANSPORT
   */
   return HEIE_UNSUPPORTED_TRANSPORT;
   }

  default:
   return HEIE_UNSUPPORTED_TRANSPORT;
  }

 return HEIE_NULL;
 }


/*
** This is the code for receiving a packet from the ethernet driver for the
given
**  device.  The response should be stored in the given response buffer -
pResponse.
**  On entry, pResponseSize contains the size of the response buffer
(pResponse).
**  On exit, pResponseSize MUST contain the number of bytes copied to the
response buffer.
**
** RETURNS:  0 on success
**           non-zero on error.
*/
int HEIIReceivePacket(HEIDevice *pDevice, BYTE *pResponse, int
*pResponseSize)
 {
 int Retval = HEIE_NULL;

 switch (pDevice->_pTransport->Transport)
  {
  case HEIT_WINSOCK:  /* GetResponse from HEIT_WINSOCK */
   {
   int NumBytes;
   SOCKET sock = (SOCKET) pDevice->_dwParam;

   if (pDevice->UseBroadcast)
    {
    struct sockaddr FromAddr;
    int FromLen = sizeof(FromAddr);

    NumBytes = recvfrom(sock, (char *) pResponse, *pResponseSize, 0,
&FromAddr, &FromLen);

    if (pDevice->pData)
     {
     /* Need to copy FROM address. */
     int Num2Copy = FromLen;

     if (pDevice->SizeOfData < Num2Copy)
      {
      Retval = HEIE_BUFFER_TOO_SMALL;
      Num2Copy = pDevice->SizeOfData;
      }

     memcpy(pDevice->pData, &FromAddr, Num2Copy);
     }
    }
   else
    {
    NumBytes = recv(sock, (char *) pResponse, *pResponseSize, 0);
    }

   if (NumBytes == SOCKET_ERROR)
    {
    /* Check to see if the error is WSAWOULDBLOCK. */
    int Error = WSAGetLastError();

    if (Error != WSAEWOULDBLOCK)
     {
     *pResponseSize = 0;
     Retval = Error;
     }
    else
     {
     Retval = HEIE_NO_RESPONSE;
     }
    }
   else
    {
    (*pResponseSize) = NumBytes;
    }

   break;
   }
  case HEIT_OTHER_TRANSPORT:
   {
   /*
   ** TODO_FOR_OTHER_SYSTEM
   ** Receive a packet for the given device into the buffer pResponse.
   ** *pResponseSize indicates the length of the pResponse buffer.
   ** If pDevice->UseBroadcast && pDevice->pData,
   ** then we need to copy the FROM address into pDevice->pData.
   ** pDevice->SizeOfData tells how long the buffer pDevice->pData is.
   ** Store the number of bytes received in (*pResponseSize).
   ** Don't return HEIE_UNSUPPORTED_TRANSPORT
   */
   return HEIE_UNSUPPORTED_TRANSPORT;
   }

  default:
   return HEIE_UNSUPPORTED_TRANSPORT;
  }

 return Retval;
 }


/*
** This is the code for sending the given packet for the given device.
** pPacket is the pointer to the actual packet data, and PacketSize is the
** number of bytes in the packet to be sent.
**
** RETURNS:  0 on success
**           non-zero on error.
*/
int HEIISendPacket(HEIDevice *pDevice, BYTE *pPacket, WORD PacketSize)
 {
 switch (pDevice->_pTransport->Transport)
  {
  case HEIT_WINSOCK:   /* Send packet of type HEIT_WINSOCK */
   {
   /* WinSock Transport. */
   SOCKET sock = (SOCKET) pDevice->_dwParam;
   if (pDevice->UseBroadcast)
    {
    /* Initialize remote address */
    struct sockaddr *pRemAddr = (struct sockaddr *) NULL;
    int SizeRemAddr = 0;
    if (pDevice->_pTransport->Protocol == HEIP_IP)
     {
     static struct sockaddr_in RemAddr;

     RemAddr.sin_family = AF_INET;
     RemAddr.sin_port = PORT_ID;
     RemAddr.sin_addr.s_addr = INADDR_BROADCAST;

     pRemAddr = (struct sockaddr *) &RemAddr;
     SizeRemAddr = sizeof(RemAddr);
     }
    else if (pDevice->_pTransport->Protocol == HEIP_IPX)
     {
     static SOCKADDR_IPX RemAddr;

     RemAddr.sa_family = AF_IPX;
     memset(RemAddr.sa_netnum, 0, 4);
     memset(RemAddr.sa_nodenum, 0xFF, 6);
     RemAddr.sa_socket = PORT_ID;
     if (pDevice->_pTransport->pSourceAddress)
      memcpy(RemAddr.sa_netnum,
pDevice->_pTransport->pSourceAddress->AddressIPX.Netnum, 4);
      /*memcpy(RemAddr.sa_netnum, &pDevice->_pTransport->NetworkAddress,
4);*/

     pRemAddr = (struct sockaddr *) &RemAddr;
     SizeRemAddr = sizeof(RemAddr);
     }
    if (sendto(sock, (char *) pPacket, PacketSize, 0, pRemAddr, SizeRemAddr)
== SOCKET_ERROR)
     return  WSAGetLastError();
    }
   else
    {
    if (send(sock, (char *) pPacket, PacketSize, 0) == SOCKET_ERROR)
     return  WSAGetLastError();
    }

   return HEIE_NULL;
   }
  case HEIT_OTHER_TRANSPORT:
   {
   /*
   ** TODO_FOR_OTHER_SYSTEM
   ** Send a packet to the given device.
   ** If pDevice->UseBroadcast, then we need to broadcast the packet.
   ** Don't return HEIE_UNSUPPORTED_TRANSPORT
   */
   return HEIE_UNSUPPORTED_TRANSPORT;
   }

  default:
   return HEIE_UNSUPPORTED_TRANSPORT;
  }
 }
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://listas.conclase.net/pipermail/cconclase_listas.conclase.net/attachments/20100501/1652f30e/attachment.html>
------------ próxima parte ------------
A non-text attachment was scrubbed...
Name: HEISrc.zip
Type: application/zip
Size: 41737 bytes
Desc: no disponible
URL: <http://listas.conclase.net/pipermail/cconclase_listas.conclase.net/attachments/20100501/1652f30e/attachment.zip>


Más información sobre la lista de distribución Cconclase