//  File Name:             IadsDS_DecomStyle.cpp
//  Project:               IadsDS
//  Author:                Mattingly, P.
//  Date:                  Nov-2005
//  Update:                Nov-2015
//
// Symvionics Inc. ("SYMVIONICS") grants a non-exclusive license for you to use
// this source code and the accompanying documentation, if any, free of charge,
// provided that this paragraph, and the following two paragraphs appear in all
// copies and in all derivative works.  In no event shall this source code or
// this license thereto impact upon or fall within the scope of any other
// agreement that you have with Symvionics.
// 
// BY USING THIS SOFTWARE, YOU FURTHER AGREE THAT, IN NO EVENT, SHALL SYMVIONICS
// BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
// CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS
// SOFTWARE, THE ACCOMPANYING DOCUMENTATION, IF ANY, OR ANY DERIVATIVE WORKS.
// YOU AGREE TO DEFEND, INDEMNIFY, AND HOLD HARMLESS SYMVIONICS FROM AND AGAINST
// ALL FINES, PENALTIES, LIABILITIES, DAMAGES, COSTS, AND EXPENSES INCURRED
// BY SYMVIONICS AS A RESULT OF YOUR USE OF THIS SOFTWARE INCLUDING THIRD PARTY
// USE OF ANY DERIVATIVE WORKS CREATED BY YOU.
// 
// SYMVIONICS SPECIFICALLY DISCLAIMS ANY AND ALL WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE.  THE SOFTWARE AND ACCOMPANYING DOCUMENTATION LICENSED
// HEREUNDER ARE PROVIDED "AS IS" WITHOUT WARRANTY OR OBLIGATION OF SUPPORT OR 
// MAINTENANCE.
//
//  PURPOSE: 
//    1. This is a demonstration program for the IADS Data Source developer to show
//       what is required to send data to the IADS Server (also know as the CDS) using
//       the IADS Custom data source ethernet protocol.
//
//  NOTES:  (This is a repeat of the "readme.txt" file that comes with this
//           Developers Kit.  Also read the IADS Real-time Data Source Interface
//           document for more complete information.)
//
//  What is this Project ?
//
//    1. The IadsDS is a Microsoft Dev Studio project that contains three different programs that
//       demonstrate sending data to the IADS Server using differnet techniques with varying
//       levels of complexity. The main purpose is for training and not production. I purposely
//       left out more complex structures so as not to hinder the understanding of the key ideas
//       of making the appropriate data packets for the IADS Server and the initial handshake required.
//    2. This source is the "Simulator" style program which creates data for Time and (4) parameters
//       all at the same sample rate, typical of Simulator systems output.  We recommend starting
//       with this exmample because it is the least complex.
//    3. There are two other data source example programs in this project, they are the
//       "IadsDS_DecomStyle" and "IadsDS_BlobStyle" styles. The Decom style creates a PCM-like memory
//       frame strucutre that replicates a buffer from a typical Decom card. This is the most complex
//       example which shows how to properly interleave data of disimilar sample rates. The Blob style
//       simulates a packet or blob of data as a single parameter. It demonstrates using a differnet
//       format (protocal) to the IADS Server.
//
//  What else is there?
//
//    1. IADS Real-time Station (RT Station) - In order to do end-to-end testing you will need to
//       either have purchased RT Station or requested from SYMVIONICS the IADS Server Developers Kit
//       which contains RT Station. This program needs to be installed on the system you are developing
//       your data source on. You will run RT Station to make a connection to your data source and display
//       data with the IADS Client, which also comes with RT Station.
//    2. IADS Real-time Data Source Interface document. This document contains a description of the protocol
//       required to send data to the IADS Server. You can get this document from our Web site along with
//       this project. It is also contained in the IADS Server Developers kit.
//
//  How do I get it?
//
//    1. You get this project and the IADS Real-time Data Source Interface document from our web site: 
//       http://iads.symvionics.com/downloads/iadsDataSource.zip
//    2. You get the Data Source Developers Kit from SYMVIONICS by request.  We can either upload it to 
//       an account for you on our FTP site: iadsfiles.symvionics.com or mail it.
//       Contact Pat Mattingly at: pmattingly@symvionics.com for the kit.
//
//  What is the The IADS Server?
//
//    The IADS Server is mentioned throughout this example; it is the software component contained
//    within the RT Station program that your data source connects to.
//
//  What are the key points?
//
//    1. Determine packet frequency.  Every data source must maintain a relatively constant
//       packet frequency of 50 packets per second. Packet rates significantly slower may
//       adversely affect the display Clients in the form of a visible ‘stutter’ during screen
//       refresh. Packet frequencies greater than 100 may affect overall throughput performance
//       and degrade the IADS Servers ability to process data.
//    2. Packet Construction - The IADS Custom data source supports two types of protocols called
//       "Frame" types.  Frame type (100) uses a "Tag/Tag/Data/Data" construction, Frame type (101)
//       uses a "Tag/Size/Data" construction useful for Blob data . At this time, data packets
//       may be comprised of only one Frame type.
//    3. It is important to build packets that interleave time words such that each sample of a
//       particular data parameter has a unique time stamp.

#include <windows.h>
#include <conio.h>
#include <stdio.h>
#include "resource.h"

#pragma warning( disable: 4244 ) // Double to float conversion
#pragma comment(lib, "wsock32.lib")

//
// Function Prototypes
//
void DataAcq(void) ;
void FillSendPacket(void) ;
void OpenSocketInterface( void ) ;
void DumpPacket( void ) ;

//
// Data Structures = Please see the IadsInterface.doc for further definition of fields
//
typedef struct
{
  int packetSize ;    // non-inclusive
  int packetCounter ; // packet counter to determine out of order packets
  int totalSent ;     // Total Packets sent
  int totalDropped ;  // Total Packets dropped
  int reserved[4] ;   // reserved for future use
} PACKET_HEADER ;

typedef struct
{
  unsigned short tag1 ; // 16 bit tag
  unsigned short tag2 ;
  union { float f; int i; unsigned int ui; } value1 ;
  union { float f; int i; unsigned int ui; } value2 ; 
} TAG_DATA_PAIR ;

typedef struct
{
  unsigned short tag ;
  union { float f ; int i ; unsigned int ui; } value ;
} TAG_DATA ;

//
// Global variables
//
int                gPortId = 49000 ; // This matches the IadsCDS.init file but can be overridden
__int64            gIrigTime = 0 ; //86400000000000 ; // IADS starts at day 1
unsigned int       gDecomStatusWord = 0;
unsigned int       gDecomStatusWord2 = 0;
unsigned int       gDecomSFCounter = 0;
unsigned int       gStatusBits = 0;
char               gEndian = 1 ;
int                gFrameType = 100 ; // tag/tag/data/data, using IADS time in total nanoseconds
char*              gSendBuf = NULL ;
PACKET_HEADER      gHeader ;
int                gPacketSize = 0 ;
TAG_DATA           gDataFrame[20][8] ; // 20 Minor Frames each 1 ms, so 20 total with 8 parameters...
float              gIndex50  = 0.0 ;
float              gIndex100 = 0.0 ;
float              gIndex200 = 0.0 ;
float              gIndex400 = 0.0 ;
float              gIndex800 = 0.0 ;
SOCKET             gAcceptSocket ;
SOCKET             gSendSocket ;
struct sockaddr_in gSocketAddr ;

//
// Routines
//
void Shutdown( void )
{
  try  
  {
    if( gSendBuf ) delete [] gSendBuf ;
    if( gAcceptSocket != INVALID_SOCKET ) closesocket( gAcceptSocket ) ;
    if( gSendSocket != INVALID_SOCKET ) closesocket( gSendSocket ) ;
  } catch(...) {} 

  WSACleanup() ;

  printf("Hit any key to exit...\n") ;

  getchar() ;
  exit(0) ;
}

//---------------------------------------------------------------------------//
//  Function:  main                                                          //
//  Author:    Mattingly, P.                                                 //
//  Date:      11-Nov-05                                                     //
//---------------------------------------------------------------------------//
//  PURPOSE:  IadsDS main program
//
//  NOTES:   
//
//  *** END FUNCTION HEADER

void main( int argc, char* argv[] )
{
  printf("*******************************************************************************\n") ;
  printf("*                                                                             *\n") ;
  printf("*          Welcome to the IADS Data Source Demonstration Program              *\n") ;
  printf("*                                                                             *\n") ;
  printf("*******************************************************************************\n\n\n") ;

	if( argc == 2 )
  {
    gPortId = atoi(argv[1]) ;
  }

//
// Build the Socket Interface
//
  OpenSocketInterface() ;

//
// Determine the size of our send data packet.  It is important to meter packets to the
// IADS Server at a rate somehwere between every 10 to 30 milliseconds. Please see Section 2
// of IADS Real-time Data Source Interface document for more detail.The next value to consider
// is the Time parameter, which in our example will occur at a sample rate of 1000 times per
// second. The time value is a 64 bit paramter in units of nanoeconds that is sent has 2
// unsigned 32 bit words. Please see Section 4.1 of the IADS Real-time Data Source Interface
// document for details. 
// **Note for Packet Format (100) each sample is 6 bytes, which is 16 bit tag, 32 bit data
// each sample for Packet Format (101) is a minimum of 32 bit tag, 32 bit size + the size of
// data.
//
//--[ DECOM Style - Packet Format 100 ]-----------------------------------------------------
//  Packet Header =                             32 +
//  TimeHigh  = 1000 sps, 20 samples in 20 ms  120 +
//  TimeLow   = 1000 sps, 20 samples in 20 ms  120 +
//  Param_50  =   50 sps,  1 sample  in 20 ms    6 + 
//  Param_100 =  100 sps,  2 samples in 20 ms   12 + 
//  Param_200 =  200 sps,  4 samples in 20 ms   24 + 
//  Param_400 =  400 sps,  8 samples in 20 ms   48 + 
//  Param_800 =  800 sps, 16 samples in 20 ms   96 + 
//  DecomStat =   50 sps,  1 sample  in 20 ms    6 + 
//------------------------------------------------------------------------------------------
//    Total Size = 72(samples) * 6(bytes:tag+data) = 432(bytes) + header(32) = 464(bytes)  
//
  // Allocate the send packet
  gPacketSize = 464 ;   
  gSendBuf = new char[gPacketSize] ;
  if( gSendBuf == NULL )
  {
    printf("*- Error: Unable to allocate memory for send buffer - quiting... \n") ;
    Shutdown() ;
  }

//
// Pre-Fill the essential header elements
//
  gHeader.packetSize = gPacketSize - 4 ;
  gHeader.packetCounter = 0 ;
  gHeader.totalSent = 0 ;
  gHeader.totalDropped = 0 ;

  int KeepRunning = 1 ;

//
// Connect to the IADS Server outer loop
//
  do 
  {
    // ***************************************************************
    // *
    // *             Wait for Connect from the IADS Server
    // *
    // ***************************************************************
    printf("Decom Style - Blocked waiting for connect on Port: ( %d )\n", gPortId ) ;

    int addrLen = sizeof( struct sockaddr_in ) ;
    gSendSocket = accept( gAcceptSocket, (struct sockaddr*)&gSocketAddr, &addrLen ) ;
    if( gSendSocket == INVALID_SOCKET) 
    {
      printf("Bad Socket on Accept - quiting...\n" ) ;
      Shutdown() ;
    }

    // *************************************************************************************
    // * Handshake - this a one-way communication.
    // *   Step 1: Send the Endian or Byte Order, Little Endian = 1, Big Endian = 2 
    // *   Step 2: Send out data format type; 100=tag/tag/data/data
    // *************************************************************************************
    if( send( gSendSocket, (char*)&gEndian, 1, 0 ) == SOCKET_ERROR )
    {
      printf("Connection Terminated - Start again...\n" ) ;
      continue ;
    }

    if( send( gSendSocket, (char*)&gFrameType, 4, 0 ) == SOCKET_ERROR )
    {
      printf("Connection Terminated - Start again...\n" ) ;
      continue ;
    }

    // ***************************************************************
    // *
    // * Data Aquisition Loop  
    // *
    // ***************************************************************
    printf("- Start data source transfer...\n\n") ;

    do 
    {
      // You will replace this routine with your method of getting data
      DataAcq() ;

      // This takes the internal array that contains the data and serializes it into a packet
      FillSendPacket() ;

      if( send( gSendSocket, (char*)&gSendBuf[0], gPacketSize, 0 ) == SOCKET_ERROR )
      {
        break ;
      }

      // This is a quick way to simulate a 20ms stream - not perfect but good enough
      // for demonstration - if your data driven then this isn't needed anyway
      ::Sleep(20) ;

    } while(!::_kbhit()) ;

    printf("- IADS Server terminated the connection - go to 'wait for connect' state...\n\n") ;

  } while( KeepRunning ) ;

  printf("Ciao...\n") ;
  Shutdown() ;
}

//---------------------------------------------------------------------------//
//  Function:  DataAcq                                                       //
//  Author:    Mattingly, P.                                                 //
//  Date:      11-Nov-05                                                     //
//---------------------------------------------------------------------------//
//  PURPOSE:  This routine fills the the send packet with incrementing ramps
//            values.
//  NOTES:   
//
// Create an interleaved frame of data parameters evenly distributing Time with Data.
// this is critical for the IADS Server. Chances are your  *real* Decom data source will
// already been distributed naturally.  If you are data driven then you can simply read
// your data source device and fill the IADS Server packet until you have reach the end
// of the time in length and send it.
//
//  *** END FUNCTION HEADER
void DataAcq(void)
{
  // Clear the tags 
  for( int r=0; r < 20; r++ ) for( int c=0; c < 8; c++ ) gDataFrame[r][c].tag = 0 ;
 
  // IADS Time words are 64 bit in length and represent both Major and Minor time in units of nanoseconds.
  // They are sent to the IADS Server as two 32 bit words using successive tag Ids as shown here.  The
  // Time value of 0 represents Day 1 or 001:00:00:00.000 Please see the IADS Real-time Data Source Interface
  // Document for more information.
  for( int ms=0; ms < 20; ms++ )
  {
    unsigned __int32 timeHigh = (unsigned __int32)(gIrigTime >> 32) ;
    unsigned __int32 timeLow = (unsigned __int32)(gIrigTime & 0xFFFFFFFF) ;

    gDataFrame[ms][0].tag = 1 ;
    gDataFrame[ms][0].value.ui = timeHigh ;
    gDataFrame[ms][1].tag = 2 ;
    gDataFrame[ms][1].value.ui = timeLow ;
    gIrigTime += 1000000 ; // increment by one millisecond in units of nanoseconds
  }

  // Decom Status - Simulated Decom Status Word.
  if( !(gIrigTime%2000000000) ) // Give user time to look at data change.
  {
    gDecomStatusWord = 0; gDecomStatusWord |= (gStatusBits << ((gDecomSFCounter*2)+2)) ; 
    if (gStatusBits >= 3) gDecomSFCounter = ++gDecomSFCounter >= 15 ? 0 : gDecomSFCounter;
    gStatusBits = ++gStatusBits > 3 ? 0 : gStatusBits;
  }

  // Data - Fill 20ms of data evenly distributed throughout the data frame based on the parameter sample rates

  // Minor frame 0
  gDataFrame[0][2].tag = 3 ;
  gDataFrame[0][2].value.f = (gIndex50  = ++gIndex50  > 49.0  ? 0.0 : gIndex50) ;
  gDataFrame[0][3].tag = 4 ;
  gDataFrame[0][3].value.f = (gIndex100 = ++gIndex100 > 99.0  ? 0.0 : gIndex100) ;
  gDataFrame[0][5].tag = 6 ;
  gDataFrame[0][5].value.f = (gIndex400 = ++gIndex400 > 399.0 ? 0.0 : gIndex400) ;
  gDataFrame[0][6].tag = 7 ;
  gDataFrame[0][6].value.f = (gIndex800 = ++gIndex800 > 799.0 ? 0.0 : gIndex800) ;
  gDataFrame[0][7].tag = 8 ;
  gDataFrame[0][7].value.i = gDecomStatusWord ;

  // Minor Frame 1
  gDataFrame[1][5].tag = 6 ;
  gDataFrame[1][5].value.f = (gIndex400 = ++gIndex400 > 399.0 ? 0.0 : gIndex400) ;
  gDataFrame[1][6].tag = 7 ;
  gDataFrame[1][6].value.f = (gIndex800 = ++gIndex800 > 799.0 ? 0.0 : gIndex800) ;

  // Minor Frame 2
  gDataFrame[2][6].tag = 7 ;
  gDataFrame[2][6].value.f = (gIndex800 = ++gIndex800 > 799.0 ? 0.0 : gIndex800) ;

  // Minor Frame 3
  gDataFrame[3][4].tag = 5 ;
  gDataFrame[3][4].value.f = (gIndex200 = ++gIndex200 > 199.0 ? 0.0 : gIndex200) ;
  gDataFrame[3][5].tag = 6 ;
  gDataFrame[3][5].value.f = (gIndex400 = ++gIndex400 > 399.0 ? 0.0 : gIndex400) ;
  gDataFrame[3][6].tag = 7 ;
  gDataFrame[3][6].value.f = (gIndex800 = ++gIndex800 > 799.0 ? 0.0 : gIndex800) ;

  // Minor Frame 4
  // This frame contains only Time words

  // Minor Frame 5
  gDataFrame[5][6].tag = 7 ;
  gDataFrame[5][6].value.f = (gIndex800 = ++gIndex800 > 799.0 ? 0.0 : gIndex800) ;

  // Minor Frame 6
  gDataFrame[6][5].tag = 6 ;
  gDataFrame[6][5].value.f = (gIndex400 = ++gIndex400 > 399.0 ? 0.0 : gIndex400) ;
  gDataFrame[6][6].tag = 7 ;
  gDataFrame[6][6].value.f = (gIndex800 = ++gIndex800 > 799.0 ? 0.0 : gIndex800) ;

  // Minor Frame 7
  gDataFrame[7][4].tag = 5 ;
  gDataFrame[7][4].value.f = (gIndex200 = ++gIndex200 > 199.0 ? 0.0 : gIndex200) ;
  gDataFrame[7][6].tag = 7 ;
  gDataFrame[7][6].value.f = (gIndex800 = ++gIndex800 > 799.0 ? 0.0 : gIndex800) ;

  // Minor Frame 8
  gDataFrame[8][6].tag = 7 ;
  gDataFrame[8][6].value.f = (gIndex800 = ++gIndex800 > 799.0 ? 0.0 : gIndex800) ;

  // Minor Frame 9
  gDataFrame[9][3].tag = 4 ;
  gDataFrame[9][3].value.f = (gIndex100 = ++gIndex100 > 99.0 ? 0.0 : gIndex100) ;
  gDataFrame[9][5].tag = 6 ;
  gDataFrame[9][5].value.f = (gIndex400 = ++gIndex400 > 399.0 ? 0.0 : gIndex400) ;
  gDataFrame[9][6].tag = 7 ;
  gDataFrame[9][6].value.f = (gIndex800 = ++gIndex800 > 799.0 ? 0.0 : gIndex800) ;

  // Minor Frame 10
  gDataFrame[10][6].tag = 7 ;
  gDataFrame[10][6].value.f = (gIndex800 = ++gIndex800 > 799.0 ? 0.0 : gIndex800) ;

  // Minor Frame 11
  gDataFrame[11][4].tag = 5 ;
  gDataFrame[11][4].value.f = (gIndex200 = ++gIndex200 > 199.0 ? 0.0 : gIndex200) ;
  gDataFrame[11][6].tag = 7 ;
  gDataFrame[11][6].value.f = (gIndex800 = ++gIndex800 > 799.0 ? 0.0 : gIndex800) ;

  // Minor Frame 12
  gDataFrame[12][5].tag = 6 ;
  gDataFrame[12][5].value.f = (gIndex400 = ++gIndex400 > 399.0 ? 0.0 : gIndex400) ;

  // Minor Frame 13
  gDataFrame[13][6].tag = 7 ;
  gDataFrame[13][6].value.f = (gIndex800 = ++gIndex800 > 799.0 ? 0.0 : gIndex800) ;

  // Minor Frame 14
  gDataFrame[14][6].tag = 7 ;
  gDataFrame[14][6].value.f = (gIndex800 = ++gIndex800 > 799.0 ? 0.0 : gIndex800) ;

  // Minor Frame 15
  gDataFrame[15][4].tag = 5 ;
  gDataFrame[15][4].value.f = (gIndex200 = ++gIndex200 > 199.0 ? 0.0 : gIndex200) ;
  gDataFrame[15][5].tag = 6 ;
  gDataFrame[15][5].value.f = (gIndex400 = ++gIndex400 > 399.0 ? 0.0 : gIndex400) ;

  // Minor Frame 16
  // This frame contains only Time words

  // Minor Frame 17
  gDataFrame[17][6].tag = 7 ;
  gDataFrame[17][6].value.f = (gIndex800 = ++gIndex800 > 799.0 ? 0.0 : gIndex800) ;

  // Minor Frame 18
  gDataFrame[18][5].tag = 6 ;
  gDataFrame[18][5].value.f = (gIndex400 = ++gIndex400 > 399.0 ? 0.0 : gIndex400) ;
  gDataFrame[18][6].tag = 7 ;
  gDataFrame[18][6].value.f = (gIndex800 = ++gIndex800 > 799.0 ? 0.0 : gIndex800) ;

  // Minor Frame 19
  gDataFrame[19][6].tag = 7 ;
  gDataFrame[19][6].value.f = (gIndex800 = ++gIndex800 > 799.0 ? 0.0 : gIndex800) ;
}

//---------------------------------------------------------------------------//
//  Function:  FillSendPacket                                                //
//  Author:    Mattingly, P.                                                 //
//  Date:      11-Nov-05                                                     //
//---------------------------------------------------------------------------//
//  PURPOSE:  This routine fills the the send packet
//
//  NOTES:   
void FillSendPacket(void) 
{
  TAG_DATA_PAIR tagDataPair = {0,0} ; // Tag Zero is illegal in my program - you'll do it diferently in your real-world data sender

  // Update those header elements that we will use in our sample program - A production version
  // could fill in the data acquisition hardware status more fully.  This Decom status ultimately gets
  // displayed in IADS.
  gHeader.packetCounter++ ;
  gHeader.totalSent++ ;

  memcpy( (char*)&gSendBuf[0], &gHeader, sizeof(PACKET_HEADER)) ;
  int bufPtr = sizeof(PACKET_HEADER) ;

  // Ok start converting from our frame format to the packet format
  for( int r=0; r < 20; r++ )
  {
    for( int c=0; c < 8; c++ )
    {
      if( gDataFrame[r][c].tag != 0 )       //  Data has been loaded into this cell
      {
        // Fill our tag data pair structure
        if( tagDataPair.tag1 == 0 )         //  Check and see if any data is already in tag1 area. 
        {
          tagDataPair.tag1 =  gDataFrame[r][c].tag ;  

          // Cheating a bit here with inherent knowledge of which tags are the time tags and those that are parameter date
          if( gDataFrame[r][c].tag < 3 )      
            tagDataPair.value1.ui =  gDataFrame[r][c].value.ui ;
          else
            tagDataPair.value1.f =  gDataFrame[r][c].value.f ;
        }
        else if( tagDataPair.tag2 == 0 ) 
        {
          tagDataPair.tag2 =  gDataFrame[r][c].tag ;

          // Cheating a bit here with inherent knowledge of which tags are the time tags and those that are parameter date
          if( gDataFrame[r][c].tag < 3 )
            tagDataPair.value2.ui =  gDataFrame[r][c].value.ui ;
          else
            tagDataPair.value2.f =  gDataFrame[r][c].value.f ;

          memcpy( (char*)&gSendBuf[bufPtr], &tagDataPair, sizeof(TAG_DATA_PAIR)) ;
          bufPtr += sizeof(TAG_DATA_PAIR) ;

          tagDataPair.tag1 = tagDataPair.tag2 = 0 ;
        }
      }
    }
  }

// Use this routine to dump the packet contents out to a file so that you can debug if the IADS Server isn't properly validing time for you
  //#define PACKET_DEBUG
#ifdef PACKET_DEBUG
  DumpPacket() ;
#endif
}

//---------------------------------------------------------------------------//
//  Function:  OpenSocketInterface                                           //
//  Author:    Mattingly, P.                                                 //
//  Date:      Nov-2015                                                      //
//---------------------------------------------------------------------------//
//  PURPOSE:  This routine Opens the socket interface on Windows OS
//
//  NOTES:   
//
//  *** END FUNCTION HEADER
void OpenSocketInterface( void )
{
  // Open on Windows
  WSADATA data ;
  int status = WSAStartup( MAKEWORD(1, 1), &data ) ;
  if( status != 0 )
  {
    printf( "Socket - socket init failed...\n" ) ;
    Shutdown() ;
  }
  // Associate the socket with the address
  memset( &gSocketAddr, 0, sizeof(gSocketAddr) )  ;
  gSocketAddr.sin_port        = htons( gPortId ) ;
  gSocketAddr.sin_family      = AF_INET ;
  gSocketAddr.sin_addr.s_addr = htonl( INADDR_ANY ) ;

  gAcceptSocket = socket( AF_INET, SOCK_STREAM, 0 ) ;
  if( gAcceptSocket == INVALID_SOCKET )
  {
    int error = WSAGetLastError() ;
    printf( "Socket - socket called failed (%d)...\n", error ) ;
    WSACleanup() ;
    Shutdown() ;
  }

  BOOL enable = 1 ;
  setsockopt( gAcceptSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&enable, sizeof(enable) );

  // Bind
  status = bind( gAcceptSocket, (struct sockaddr*)&gSocketAddr, sizeof(struct sockaddr) ) ;
  if( status != 0 )
  {
    printf( "Socket - socket init failed...\n" ) ;
    Shutdown() ;
  }

  // Listen
  status = listen( gAcceptSocket, 1 ) ;
  if( status != 0 )
  {
    printf( "Socket - socket init failed...\n" ) ;
    Shutdown() ;
  }
}

//---------------------------------------------------------------------------//
//  Function:  DumpPacket                                                    //
//  Author:    Mattingly, P.                                                 //
//  Date:      11-Nov-05                                                     //
//---------------------------------------------------------------------------//
//  PURPOSE:  This routine fills the the send packet
//
//  NOTES:   
void DumpPacket( void )
{
  static int nWrite = 0 ;
  static FILE* fp = fopen( "debug.txt", "w" ) ;

  if( nWrite < 100 )
  {
    TAG_DATA_PAIR tdp = {0,0} ;

    fprintf( fp, "-----------------------------\n") ;
    for( int ptr=sizeof(PACKET_HEADER); ptr < gPacketSize; ptr+=sizeof(TAG_DATA_PAIR) )
    {
      memcpy( (char*)&tdp, (char*)&gSendBuf[ptr], sizeof(TAG_DATA_PAIR) ) ;
      fprintf( fp, "%d, %d, ", tdp.tag1, tdp.tag2 ) ;
      if( tdp.tag1 > 5 )
        fprintf( fp, "%d, ", tdp.value1.i ) ;
      else
        fprintf( fp, "%f, ", tdp.value1.f ) ;
      if( tdp.tag2 > 5 )
        fprintf( fp, "%d\n", tdp.value2.i ) ;
      else
        fprintf( fp, "%f\n", tdp.value2.f ) ;
    }
  }
  else if( nWrite == 100 )
  {
    fclose( fp ) ;
  }

  nWrite++ ;
}
