//===========================================================================
//  Copyright 2000 by UMM Electronics, Inc.                                 
//                                                                          
//  File Name: z_stubs.c                                                    
//                                                                          
//  File Description: Main Emulator File for the RTP                                                       
//                                                                          
//  Project Name:  Mercury                                                  
//                                                                          
//  Author: C.S. Borowicz                   Creation Date:  29/May/98
//                                                                          
//  Requirements:                                                           
//                                                                          
//  Revision History:                                                       
//                08/31/99 SEP mah, modified for lead-lag photo-diodes
//          03/13/00 PN, Major modifications to allow different RTP
//                 results and a CSV file for key mapping
//  $Revision::   1.19   $                                                    
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
//        Include Files
//---------------------------------------------------------------------------
#include "uip_cnfg.h"
#ifndef __UIP_RTP_INTEGRATION__
#include <ctype.h>
#include    "myio.h"
#include <stdlib.h>
#include <time.h>               //  Include file for time_t.               
#include <string.h>
#include <math.h>
#include "ui_clktm.h"

#include "gg_lit11.h"           //  Include file for GG Layer.             

#include "cnv_data.h"           //  Include file for converting data       
#include "cnv_disk.h"           //  Include file for                       
#include "db_platt.h"           //  Include file for platter functions     
#include "db_tests.h"           //  Include file for tests.                
#include "dec_bar.h"            //  Include file for barcode_label_t       
#include "ipc_txrx.h"           //  Include file for UIP/RTP messages      
#ifndef TARGET_HARDWARE
#include "prt_thrm.h"           //  Include file for printer.              
#include "remark.h"
#endif
                                 
#include "z_stubs.h"            //  Header file for these functions.       
#include "db_cal.h"
#include "uip_util.h" 
#include "scr_lib.h"


//---------------------------------------------------------------------------
//            Shared Data
//---------------------------------------------------------------------------

#ifndef TARGET_HARDWARE
BOOLEAN Print_Card_Inserted = FALSE;
static char CSV_Files[6][255] = {0};
static int  CSV_Slot_No[6] = {0};
static int  Slot_To_LED[6] = {0};
#endif

//---------------------------------------------------------------------------
//            Preprocessor Macros                                               
//---------------------------------------------------------------------------

// for use with Create_Cartridge arguments
#define MIN_DAY      1L
#define MAX_DAY     31L
#define MIN_MONTH    1L
#define MAX_MONTH   12L
#define MIN_YEAR  1970L
#define MAX_YEAR  2225L

//---------------------------------------------------------------------------
//        File Scope Structure and ENUM Type Definitions
//---------------------------------------------------------------------------
/*
 *  States for return of results data
 */
typedef enum
{
    RESULT_IDLE,
    RESULT_INIT,
    RESULT_DRY_LED,
    RESULT_TRACE_STDS,
    RESULT_STDS,
    RESULT_DRY,
    RESULT_TRACE,
    RESULT_CURVE
} states_t;

/*
 *  Endian convesion for return of results data
 */
typedef union
{
    BYTE  Byte_Array[4];
    float Floating_Point;
    DWORD Long_Int;
} Type_32_Bits;                         

typedef union
{
    BYTE Byte_Array[2];
    WORD Short_Int;
} Type_16_Bits;                         

/****************************************************************************
*                        <<< Static Variables >>>                           *
****************************************************************************/
static DWORD RTP_TIME_INC;
static BOOLEAN SlotUsed[6] = {FALSE,FALSE,FALSE,FALSE,FALSE,FALSE};
static BOOLEAN LedsUsed[7] = {FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE};
static BOOLEAN IQC_Platter; 
static BYTE   IQC_Led_Num;

static BOOLEAN card_inserted = FALSE;
static BOOLEAN disk_inserted = FALSE;
static BOOLEAN still_upgrading = TRUE;
static BOOLEAN Error_Pending = FALSE;
static int  upgrade_error = 0;

static Cart_Options_e CartType[6] =
{
    CART_FILM_TYPE,
    CART_FILM_TYPE,
    CART_FILM_TYPE,
    CART_FILM_TYPE,
    CART_FILM_TYPE,
    CART_FILM_TYPE
};

static Cart_Options_e CartType2[6] =
{
    CART_FILM_TYPE,
    CART_FILM_TYPE,
    CART_FILM_TYPE,
    CART_FILM_TYPE,
    CART_FILM_TYPE,
    CART_FILM_TYPE
};

static int traces[6][4];

static UCHAR platter_slot[6] = { 1, 4, 5, 2, 3, 6 };



//---------------------------------------------------------------------------
//        File Scope (internal) Function Prototypes
//---------------------------------------------------------------------------
int send_test_data (IPC_msg_t *ReturnBuff);
void CurveInit (void);
void BuildTrace (int Slot,IPC_msg_t *ReturnBuff);
void BuildTraceEch (int Slot,IPC_msg_t *ReturnBuff);
void BuildTraceCoag (int Slot,IPC_msg_t *ReturnBuff);
void BuildStandard (int Curve,IPC_msg_t *ReturnBuff);
void BuildTestCurve (int Curve,IPC_msg_t *ReturnBuff);
void BuildTestCurveEch (int Curve,IPC_msg_t *ReturnBuff);
void BuildTestCurveCoag (int Curve,IPC_msg_t *ReturnBuff);
void BuildTestCurveIQC (Cart_Options_e carttype2, int Curve, BYTE led_num, IPC_msg_t *ReturnBuff);
void BuildDryCoag (int Curve,IPC_msg_t *ReturnBuff);
void BuildDryFilm (int Curve,IPC_msg_t *ReturnBuff);
void Create_Cartridge(long id, long month, long day, long year, long lot,
                      IPC_msg_t* return_data);
void scan_keymap_file(char ch, IPC_msg_t* Return_Data);   
void csv_parse(char *buf,int *id,int *month,int *day,int *year,int *lot_num, char *filename, int* use_slot_no);


// CSV data file functions
BOOLEAN LoadCurveFromCSV(const char * filename, int slot_no, int use_slot_no, IPC_msg_t *databuf, 
                         BOOLEAN dry_data, int test_id, int led);
BOOLEAN LoadTraceFromCSV(const char * filename, int slot_no, int use_slot_no, IPC_msg_t *databuf, int test_id);
void serialize_message_file(const char *filename, IPC_msg_t* Return_Data);

//===========================================================================
//  Function Name: ipc_process_rcvd_message                                 
//                                                                          
//  Description:                                                            
//      This function simulates receiving messages from the RTP.  These     
//  messages include warmed up, cartridge inserted, cartridge ejected and   
//  other messages generated while the unit is running.                     
//                                                                          
//  Inputs:                                                                 
//      Return_Data - pointer to message structure.                         
//                                                                          
//  Outputs:                                                                
//      Always returns TRUE.                                                
//---------------------------------------------------------------------------
BYTE ipc_process_rcvd_message(IPC_msg_t* Return_Data)
{ 
    char            ch = 0;
    unsigned char   tmp_char[240];

    int tmp_error;
    int j=0;
    
    static char stat_strings[][15] =
    {                                                                                     
        "NOT COMPLETED",
        "IN RANGE",
        "REF RANGE LO",
        "REF RANGE HI",
        "ALERT RANGE LO",
        "ALERT RANGE HI",
        "DYN RANGE LO",
        "DYN RANGE HI"
    };
    static int pending_key = '\0';

    if (pending_key == '\0' && kbhit ()) // if no pending key and new key press
    {                // note if pending operations we don't look at the next key yet
        ch = (char)getch();
        ch = toupper(ch);
        
        switch (ch)
        {
               
            // If the ESC key is pressed, gracefully shut down.
            // This is only useful in a simulation setting.
            case 27:
                Return_Data->ID = 0xFF;
                Return_Data->byte_cnt = NO_DATA;
                *Return_Data->data_ptr = NO_DATA;
                break;

            // Simulate the reception of an 'RTP POST Results' msg
            case ' ':   // Deal with a POST passed condition 

                Return_Data->ID = (int)MSG_POST_RESULTS;
                Return_Data->byte_cnt = 14;
                
                for (j=0; j < 10; j++) tmp_char[j] = 0x30;
                tmp_char[10] = 0x00;
                tmp_char[11] = 0x01;
                tmp_char[12] = 0x28;
                tmp_char[13] = (BYTE)POST_RTP_HL_PASS; 
                memcpy(Return_Data->data_ptr, &tmp_char[0], Return_Data->byte_cnt);
                
                break;
        
            case 'X':   // Deal with a POST failed condition 

                Return_Data->ID = (int)MSG_POST_RESULTS;
                Return_Data->byte_cnt = 14;
                
                for (j=0; j < 10; j++) tmp_char[j] = 0x30;
                tmp_char[10] = 0x00;
                tmp_char[11] = 0x00;
                tmp_char[12] = 0x31;
                tmp_error = ( rand( ) % ( MAX_POST_ERROR_INDEX - 1 ) ) + 1;
                tmp_char[13] = (BYTE)tmp_error;
                memcpy(Return_Data->data_ptr, &tmp_char[0], Return_Data->byte_cnt);
                
                break;


            case '?':
                Return_Data->ID = (int)MSG_SYSTEM_MODE_CMPL;
                Return_Data->byte_cnt = NO_DATA;
                *Return_Data->data_ptr = NO_DATA;
                break;
                
            /*
             * Simulate the reception of an 'RTP Abort Test' msg
             */
            case 'A':
            
                Return_Data->ID = (int)MSG_USER_ABORT_TEST_CMPL;
                Return_Data->byte_cnt = 3;
                tmp_char[0] = 0x0D;
                tmp_char[1] = 0x12;
                tmp_char[2] = 0x34; 
                memcpy(Return_Data->data_ptr, &tmp_char[0], Return_Data->byte_cnt);
                
                break; 
                
            /*
             * Simulate the reception of a 'Door Status' msg
             */
            case 'O':   /* Deal with 'Door has been opened' condition */
                
                Return_Data->ID = (int)MSG_DOOR_POSITION;
                Return_Data->byte_cnt = 1;
                tmp_char[0] = INS_DOOR_OPENED; 
                memcpy(Return_Data->data_ptr, &tmp_char[0], Return_Data->byte_cnt);

                break;
                
            case 'C':   /* Deal with 'Door has been closed' condition */
                
                Return_Data->ID = (int)MSG_DOOR_POSITION;
                Return_Data->byte_cnt = 1;
                tmp_char[0] = INS_DOOR_CLOSED; 
                memcpy(Return_Data->data_ptr, &tmp_char[0], Return_Data->byte_cnt);
                
                break;
                
            /*
             * Simulate the reception of a 'Cartridge(s) Ejected' msg
             */
            case 'E':   /* Deal with 'most recently inserted cart has been ejected' condition */
                
                Return_Data->ID = (int)MSG_CART_EJECTED;
                Return_Data->byte_cnt = 1;
                tmp_char[0] = LAST_CARTRIDGE_EJECTED; 
                memcpy(Return_Data->data_ptr, &tmp_char[0], Return_Data->byte_cnt);
                
                break;
                
            case 'F':   /* Deal with 'All cartridges have been ejected' condition */
                
                Return_Data->ID = (int)MSG_CART_EJECTED;
                Return_Data->byte_cnt = 1;
                tmp_char[0] = ALL_CARTRIDGES_EJECTED; 
                memcpy(Return_Data->data_ptr, &tmp_char[0], Return_Data->byte_cnt);
                
                break;
                
                                
            /*
             * Simulate the reception of a 'Test Results' msg
             */
            case ']':

                Return_Data->ID = (int)MSG_TEST_RESULTS;
                pending_key = send_test_data( Return_Data ); // try to setup for sending   
                break;
                
            /*
             * Simulate the reception of a 'Chamber Up To Temperature' msg
             */
            case 'W':
                
                Return_Data->ID = (int)MSG_CHAMBER_WARMED;
                Return_Data->byte_cnt = NO_DATA;
                *Return_Data->data_ptr = NO_DATA;

                break;  
                
            /*
             * Simulate the reception of a 'RTP Error' msg
             */
            case 'Q':
                Return_Data->ID = (int)MSG_ERROR_IN_RTP;
                Return_Data->byte_cnt = 9;
                


                //tmp_char[0] = 0x55;
                //for (j=1; j<9; j++)
                //  tmp_char[j] = (BYTE)( ( rand( )%255 ) + 1 );

                //for a real customer error
                tmp_char[0] = 0xAA;
                tmp_char[1] = 255;
                tmp_char[2] = 0;
                tmp_char[3] = 6;
                tmp_char[4] = 53;
                tmp_char[5] = 255;
                tmp_char[6] = 255;
                tmp_char[7] = 255;
                tmp_char[8] = 255;



                memcpy(Return_Data->data_ptr, &tmp_char[0], Return_Data->byte_cnt);
                
                break;
            
            // Simulate the reception of a 'RTP Error' msg
            case 'L':
                Return_Data->ID = (int)MSG_ERROR_IN_RTP;
                Return_Data->byte_cnt = 9;
                
                tmp_char[0] = 0xAA;
                tmp_char[1] = 255;
                tmp_char[2] = 0;
                tmp_char[3] = 6;
                tmp_char[4] = 53;

                memcpy(Return_Data->data_ptr, &tmp_char[0], Return_Data->byte_cnt);
                
                break;
                
            case 'Z':
                uip_set_uip_cmd(UIP_CMD_PRINT_ALL_QC);
                break;    
                
            // Simultate the reception of an invalid barcode label             
            case '|':
                
                Return_Data->ID = (int)MSG_BARCODE_RESULTS;
                Return_Data->byte_cnt = 37;
                    
        // Invalid Cartridge ID (ID n/a)
                tmp_char[0]  = (UCHAR)0x00;  
                
                for (j=1; j<37; j++) 
                  tmp_char[j]  = 0x00; 
                memcpy(Return_Data->data_ptr, &tmp_char[0], Return_Data->byte_cnt);
                
                break;

            // Simulate the reception of a 'RTP Abort Test' msg 
            case ':':
            
                Return_Data->ID = (int)MSG_TEST_ABORTED_RTP;
                Return_Data->byte_cnt = 8;
                
                for (j=0; j < 8; j++)
                  tmp_char[j] = (BYTE)( ( rand( )%255 ) + 1 );
                memcpy(Return_Data->data_ptr, &tmp_char[0], Return_Data->byte_cnt);

                break;                
            
            case ';':

                Return_Data->ID = (int)MSG_IQC_RESULTS;
                Return_Data->byte_cnt = 0;
                
                break;
                
            case 'I':
                Print_Card_Inserted = TRUE;
                break;
            case 'U':
                Print_Card_Inserted = FALSE;
                break;
            
            case 'M': // raise MOT error
                Return_Data->ID = MSG_ERROR_IN_RTP;
                Return_Data->byte_cnt = 9;
                
                Return_Data->data_ptr[0] = 0x55;       // commanded, can retry
                Return_Data->data_ptr[1] = 255;       // Task ID
                Return_Data->data_ptr[2] = 0;       // RTP state
                Return_Data->data_ptr[3] = 5; // L0 module id
                Return_Data->data_ptr[4] = 28;         // L0 module error code
                Return_Data->data_ptr[5] = 4;          // L1...              
                Return_Data->data_ptr[6] = 69;
                Return_Data->data_ptr[7] = 255;        // L2...
                Return_Data->data_ptr[8] = 255;
                break;
                
            case 'Y': 
                Return_Data->ID = 200;
                Return_Data->byte_cnt = 1;                
                Return_Data->data_ptr[0] = 5;
                
                //serialize_message_file("recxmit.txt", Return_Data);
                break;
                
            default:  
              // search keymap.csv for barcode label generation
              scan_keymap_file(ch, Return_Data);        
                break;
            
        }  // end switch 
    }  // end if 

    else // if pending key
        switch (pending_key) // determine what pending operation to do
        {
            case ']': // not done with sending film data yet
                pending_key = send_test_data (Return_Data); // try to send blocks of data
                break;

            default : // safety net
                pending_key = '\0'; // stop 
                break;
        }
    
    return(TRUE);
    
}  // end of Process_Rcvd_Message 


//---------------------------------------------------------------------------
//  Function Name: send_test_data                                           
//                                                                          
//  Description: Send the test results to simulate rtp data return.         
//                                                                          
//  Inputs:                                                                 
//     Arguments:                                                           
//        ReturnBuff structure which contains data stream and attributes.   
//     Global:                                                              
//        SlotUsed   array indicating if current slot used                  
//        LedsUsed   array indicating if current led used                                                                                             
//
//  Outputs:                                                                
//     Pending indicates if we are to continue, ']' / '\0' = yes / no.      
//---------------------------------------------------------------------------
int send_test_data (IPC_msg_t *ReturnBuff)
{
    static states_t State = RESULT_INIT;
    static int      Slot;
    static int      Led;
    static int      Standard;
    int             Pending;
    int             i;
    BOOLEAN         done;

    ReturnBuff->byte_cnt = 0; /* set up to determine if used */

    switch (State)
    {
        case RESULT_INIT:
            IQC_Platter = FALSE;
            IQC_Led_Num = 0;

            CurveInit ();

            Slot = 0;
            Led = 0;
            Standard = 7;        /* Range is 7 thru 21 */
            State = RESULT_DRY_LED; 
            break;

        case RESULT_DRY_LED:  
            if (IQC_Platter)
                State = RESULT_TRACE_STDS;
            else
            {     
              if (LedsUsed[Led] == TRUE)
                {
                // first, try to build the standards from provided data files
                done = FALSE;
                for (i = 0; i < 6 && !done; i++)
                  if (CSV_Slot_No[i] != 0)
                    if (LoadCurveFromCSV(CSV_Files[i], Standard + Led, 0, ReturnBuff, TRUE, CART_FILM_TYPE, Led))
                      done = TRUE;
                  
                  
                if (!done)
                  BuildDryFilm (Standard + Led,ReturnBuff); /* need 1 based number */
                
                }
                
                
                if (Standard < LED1_DAT_BLK_STAND)  /* same state */
                    Standard += 7;
                else /* see if we ran out of leds to check */
                {
                    Standard = LED1_DAT_W1_STAND;

                    if (Led < 6)  /* same state */
                        Led++;
                    else          /* next state */
                    {
                        Led = 0;
                        State = RESULT_TRACE_STDS;
                    }
                }
            }
            
            break;

        case RESULT_TRACE_STDS:
            if (IQC_Platter)
                State= RESULT_STDS;
            else
            {   
                if (LedsUsed[Led] == TRUE)           /* if current led used */
                  {
                  // first, try to build the standards from provided data files
                  done = FALSE;
                  for (i = 0; i < 6 && !done; i++)
                    if (CSV_Slot_No[i] != 0)
                      if (LoadTraceFromCSV(CSV_Files[i], Standard + Led, 0, ReturnBuff, CART_FILM_TYPE))
                        done = TRUE;
                    
                    
                  if (!done)  
                    BuildTrace (Standard + Led,ReturnBuff); /* need 1 based number */
                  }


                if (Standard < LED1_DAT_BLK_STAND)  /* same state */
                    Standard += 7;
                else /* see if we ran out of leds to check */
                {
                    Standard = LED1_DAT_W1_STAND;

                    if (Led < 6)  /* same state */
                        Led++;
                    else          /* next state */
                    {
                        Led = 0;
                        State = RESULT_STDS;
                    }
                }
            }
            
            break;

        case RESULT_STDS:          
            
            if (LedsUsed[Led] == TRUE)           /* if current led used */
              {
              // first, try to build the standards from provided data files
              done = FALSE;
              for (i = 0; i < 6 && !done; i++)
                if (CSV_Slot_No[i] != 0)
                  if (LoadCurveFromCSV(CSV_Files[i], Standard + Led, 0, ReturnBuff, FALSE, CART_FILM_TYPE, Led))
                    done = TRUE;
                
                
              if (!done)  
                BuildStandard (Standard + Led,ReturnBuff); /* need 1 based number */
              }

            if (Standard < LED1_DAT_BLK_STAND)  /* same state */
                Standard += 7;
            else /* see if we ran out of leds to check */
            {
                Standard = 7;

                if (Led < 6)  /* same state */
                    Led++;
                else          /* next state */
                    State = RESULT_DRY;
            }

            break;

        case RESULT_DRY:     
            if (IQC_Platter)
                State = RESULT_TRACE;
            else
            {
                if (SlotUsed[Slot] == TRUE)      /* if current slot used */
                {
                    switch (CartType[Slot])
                    {
                        case CART_FILM_TYPE:
                            if ( CSV_Slot_No[Slot] != 0 )
                              {
                              LoadCurveFromCSV(CSV_Files[Slot], Slot + 1, CSV_Slot_No[Slot], ReturnBuff, TRUE, CartType[Slot], Led);
                              }
                            else
                              BuildDryFilm (Slot + 1,ReturnBuff); /* need 1 based number */
                            break;
                        case CART_ECH_TYPE:
                            break;
                        case CART_COAG_TYPE:
                            break;
                        default:
                            break;
                    }
                }

                if (Slot < 5)  /* same state */
                {
                    Slot++;
                }
                else          /* next state */
                {
                    State = RESULT_TRACE;
                    Slot = 0;
                }
            }

            break;

        case RESULT_TRACE:         
            if (IQC_Platter)
                State = RESULT_CURVE;
            else
            {
                if (SlotUsed[Slot] == TRUE)       /* if current slot used */
                {
                    switch (CartType[Slot])
                    {
                        case CART_FILM_TYPE:
                            if ( CSV_Slot_No[Slot] != 0 )
                              {
                              LoadTraceFromCSV(CSV_Files[Slot], Slot + 1, CSV_Slot_No[Slot], ReturnBuff, CartType[Slot]);
                              }
                            else
                              BuildTrace (Slot + 1,ReturnBuff); /* need 1 based number */
                            break;
                        case CART_ECH_TYPE:
                            if ( CSV_Slot_No[Slot] != 0 )
                              {
                              LoadTraceFromCSV(CSV_Files[Slot], Slot + 1, CSV_Slot_No[Slot], ReturnBuff, CartType[Slot]);
                              }
                            else
                              BuildTraceEch (Slot + 1,ReturnBuff); /* need 1 based number */
                            break;
                        case CART_COAG_TYPE:
                            if ( CSV_Slot_No[Slot] != 0 )
                              {
                              LoadTraceFromCSV(CSV_Files[Slot], Slot + 1, CSV_Slot_No[Slot], ReturnBuff, CartType[Slot]);
                              }
                            else
                              BuildTraceCoag (Slot + 1,ReturnBuff); /* need 1 based number */
                            break;
                        default:
                            break;
                    }
                }

                if (Slot < 5) /* same state */
                {
                    Slot++;
                }
                else          /* next state */
                {
                    State = RESULT_CURVE;
                    Slot = 0;
                }
            }
            
            break;

        case RESULT_CURVE:
            if (SlotUsed[Slot] == TRUE)    /* if current slot used */
            { 
                switch (CartType[Slot])
                {
                    case CART_FILM_TYPE:
                        if ( CSV_Slot_No[Slot] != 0 )
                          {
                          LoadCurveFromCSV(CSV_Files[Slot], Slot + 1, CSV_Slot_No[Slot], ReturnBuff, FALSE, CartType[Slot], Led);
                          }
                        else
                          BuildTestCurve (Slot + 1,ReturnBuff); /* need 1 based number */
                        break;
                    case CART_ECH_TYPE:
                        if ( CSV_Slot_No[Slot] != 0 )
                          {
                          LoadCurveFromCSV(CSV_Files[Slot], Slot + 1, CSV_Slot_No[Slot], ReturnBuff, FALSE, CartType[Slot], Led);
                          }
                        else
                          BuildTestCurveEch (Slot + 1,ReturnBuff); /* need 1 based number */
                        break;
                    case CART_COAG_TYPE:
                        if ( CSV_Slot_No[Slot] != 0 )
                          {
                          LoadCurveFromCSV(CSV_Files[Slot], Slot + 1, CSV_Slot_No[Slot], ReturnBuff, FALSE, CartType[Slot], Led);
                          }
                        else
                          BuildTestCurveCoag (Slot + 1,ReturnBuff); /* need 1 based number */
                        break;
                        
                    case CART_IQC_TYPE:                      
                      if (CartType2[Slot] == CART_FILM_TYPE)
                      {
                        if (++IQC_Led_Num == 7)
                          IQC_Led_Num = 0;
                        //printf("iqc_led_num = %i, slot = %i, slot_no = %i\n", IQC_Led_Num, Slot, CSV_Slot_No[Slot]);getch();
                        if (IQC_Led_Num)
                          {
                            if (CSV_Slot_No[Slot] != 0)
                              LoadCurveFromCSV(CSV_Files[Slot], Slot + 1, CSV_Slot_No[Slot], 
                                               ReturnBuff, FALSE, CartType[Slot], IQC_Led_Num);
                            else
                              BuildTestCurveIQC(CartType2[Slot], Slot+1, IQC_Led_Num, ReturnBuff);
                          }
                      }
                      else
                          BuildTestCurveIQC(CartType2[Slot], Slot+1, IQC_Led_Num, ReturnBuff);
                        break;
                    default:
                        break;
                }
            }

            if ((CartType[Slot] == CART_IQC_TYPE) && (CartType2[Slot] == CART_FILM_TYPE))
            {       
                if (IQC_Led_Num == 0)
                {
                    if (Slot < 5)  /* same state */
                    {
                        Slot++;
                    }
                    else          /* next state */
                    {
                        State = RESULT_IDLE;
                        Slot = 0;
                    }
                }
            }
            else
            {
                if (Slot < 5)  /* same state */
                {
                    Slot++;
                }
                else          /* next state */
                {
                    State = RESULT_IDLE;
                    Slot = 0;
                }
            }
      
            break;

    } /* end switch (State) */


    /*
     * Now, set the return value.  If the state variable is non-idle, then
     * return the pending key value.  If the state variable is idle, then
     * return '\0'.
     */
    if (State != RESULT_IDLE)
    {
        Pending = ']';
    }
    else
    {
        Pending = '\0';
        State = RESULT_INIT;
    }

    /*
     * If the byte count is 0, make the return data harmless.
     */ 
    if (ReturnBuff->byte_cnt == 0)
    {
        ReturnBuff->ID = (int)NO_DATA;
        ReturnBuff->byte_cnt = NO_DATA;
        *ReturnBuff->data_ptr = NO_DATA;
    }
    else /* else mark as results */
    {
        ReturnBuff->ID = (int)MSG_TEST_RESULTS;
    }

    return (Pending);
} /* end of send_test_data */

/****************************************************************************
*                          <<< Code Block >>>                               *
*                                                                           *
*   Function Name: CurveInit                                                *
*                                                                           *
*   Description: Initialize for simulation of results data return.          *
*                                                                           *
*   Inputs:                                                                 *
*      Arguments:                                                           *
*         N/A                                                               *
*      Global:                                                              *
*         SlotUsed     array indicating if current slot used                *
*         LedsUsed     array indicating if current led used                 *
*         RTP_TIME_INC determines platter wide time increment for tests.    *
*                                                                           *
*   Outputs:                                                                *
*      N/A                                                                  *
*                                                                           *
****************************************************************************/
void CurveInit (void)
{
    int a,i,j;
    Barcode_Label_t     CartRec;
    CartToAnal_t        CartList;
    Test_Parameter_t    AnalyteRec;
    int slot;

    /*
     * Initialize for sending film test data
     */
    RTP_TIME_INC = 4000L;

    for (i=0; i<6; i++)
        SlotUsed[i] = FALSE;

    for (i=0; i<7; i++)
        LedsUsed[i] = FALSE;

    for (i=0; i<6; i++)
    {
        for (j=0; j<4; j++)
        {
            traces[i][j] = -1;
        }
    }


    /*
     * remember cartridge data
     */
    for (i=db_get_num_inserted_carts(); i>0; i--)
    {
        /*
         * map from current slot to get cartridge info,
         * map from cartridge id to get analyte info
         * then from analyte info collect needed data
         */
        slot = platter_slot[i-1];
        db_get_cart_rec ((BYTE)slot,&CartRec);
        db_get_CartToAnal_rec (CartRec.cart_id, &CartList);
        db_find_analyte_rec(CartList.analyte_id[0], &AnalyteRec);

        switch (AnalyteRec.fixed_param.cart_type)
        {
            case CART_FILM_TYPE:
                SlotUsed[slot - 1] = TRUE; /* slots and leds are 1 based numbers */
                LedsUsed[AnalyteRec.rtp_param.led_number - 1] = TRUE;
                Slot_To_LED[slot - 1] = AnalyteRec.rtp_param.led_number;
                CartType[slot - 1] = CART_FILM_TYPE;
                for (j=0; j<4; j++)
                    traces[slot - 1][j] = AnalyteRec.rtp_param.trace_tx[j];

                break;

            case CART_ECH_TYPE:  
                SlotUsed[slot - 1] = TRUE;
                CartType[slot - 1] = CART_ECH_TYPE;
                for (j=0; j<4; j++)
                    traces[slot - 1][j] = AnalyteRec.rtp_param.trace_tx[j];

                break;

            case CART_COAG_TYPE:
                SlotUsed[slot - 1] = TRUE;
                CartType[slot - 1] = CART_COAG_TYPE;
                for (j=0; j<4; j++)
                    traces[slot - 1][j] = AnalyteRec.rtp_param.trace_tx[j];

                break;

            case CART_IQC_TYPE:  
                IQC_Platter = TRUE;
                SlotUsed[slot - 1] = TRUE;
                CartType[slot - 1] = CART_IQC_TYPE;

                switch (CartRec.cart_type)
                {                      
                    case BAR_REF_IQC_TYPE:
                        CartType2[slot - 1] = CART_FILM_TYPE;
                        break;
                    case BAR_ECH_IQC_TYPE:
                        CartType2[slot - 1] = CART_ECH_TYPE;
                        break;
                    case BAR_TRNS_IQC_TYPE:
                        CartType2[slot - 1] = CART_COAG_TYPE;
                        break;
                    case BAR_FILM_TYPE:
                    case BAR_ECH_TYPE:
                    case BAR_COAG_TYPE:
                    case BAR_FACT_TYPE:
                    default:
                        CartType2[slot - 1] = CART_NON_TYPE;
                        break;
                }
                
                for (a=0; a<CartList.num_of_analytes_in_cart; a++)
                {                                     
                    db_find_analyte_rec(CartList.analyte_id[a], &AnalyteRec);
                    if (AnalyteRec.rtp_param.led_number > 0)
                        LedsUsed[AnalyteRec.rtp_param.led_number-1] = TRUE;
                }

                break;

            default:
                break;
        }
    }
}  /* end of CurveInit */

/****************************************************************************
*                          <<< Code Block >>>                               *
*                                                                           *
*   Function Name: BuildTrace                                               *
*                                                                           *
*   Description: Build trace curve for simulation of results data return.   *
*                                                                           *
*   Inputs:                                                                 *
*      Arguments:                                                           *
*         Curve        trace slot (number) to build.                        *
*         ReturnBuff   structure which contains data stream and attributes. *
*      Global:                                                              *
*         RTP_TIME_INC determines platter wide time increment for tests.    *
*                                                                           *
*   Outputs:                                                                *
*      N/A                                                                  *
*                                                                           *
****************************************************************************/
#pragma optimize( "lge", off )
void BuildTrace (int Slot,IPC_msg_t *ReturnBuff)
{
    DWORD RTP_Time;
    unsigned char *tmp_char;    /* buffer pointer */
    int i,j,k;
    Type_32_Bits Swap_32;
    Type_16_Bits Swap_16;
    Type_16_Bits Scaled_16;

    RTP_Time = 4000L;

    ReturnBuff->byte_cnt = (1 + 1 + 1 + 1 + 4 + 4 * (2 + 2 + 4 + 100 * 4 * 2));

    tmp_char = ReturnBuff->data_ptr;

    *(tmp_char++) = TESTRES_FILM;
    *(tmp_char++) = (UCHAR)Slot; /* put slot number here */

    *(tmp_char++) = 0x01;       /* indicate trace data */
    *(tmp_char++) = 0x0;

    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;
       
       
    for (i = 0;i < 4;i++) /* 3 trace points for now */
    {
        *(tmp_char++) = (UCHAR)(0xff);   /* separator */
        *(tmp_char++) = (UCHAR)(0xff);

        Swap_16.Short_Int = Slot - 1;    /* need 0 based number here */
        Swap_16.Short_Int = ipc_word_swap(Swap_16.Short_Int);

        for (j = 0;j < sizeof(WORD);j++) /* store raw data type */
            *(tmp_char++) = Swap_16.Byte_Array[j];

        if (Slot <= 6 && traces[Slot-1][i] >= 0)
        {
            RTP_Time = 1000L * traces[Slot-1][i] + i * 100;
        }

        Swap_32.Long_Int = RTP_Time;     /* get current rtp time */
        Swap_32.Long_Int = ipc_long_swap(Swap_32.Long_Int);

        for (j = 0;j < sizeof(DWORD);j++) /* store rtp time */
            *(tmp_char++) = Swap_32.Byte_Array[j];

        RTP_Time += RTP_TIME_INC;         /* increment rtp time */

        for (j = 0;j < 100;j++) /* loop thru first 100 raw a/d counts */
        {
            /*
            ** calculate full and scaled values
            */
              Swap_32.Floating_Point  = (float)j;
              Swap_32.Floating_Point *= 0.6464f;
              Swap_32.Floating_Point  =
                Swap_32.Floating_Point * Swap_32.Floating_Point;
              Swap_16.Short_Int       = (WORD)(Swap_32.Floating_Point);
            Scaled_16.Short_Int       = 4095 - Swap_16.Short_Int / 16;

            /*
            ** now swap them
            */
              Swap_16.Short_Int = ipc_word_swap(  Swap_16.Short_Int);
            Scaled_16.Short_Int = ipc_word_swap(Scaled_16.Short_Int);

            for (k = 0;k < sizeof(WORD);k++) /* now store them and mirrored versions */
            {
                *(tmp_char + (  0 + j) * sizeof(WORD) + k) =   Swap_16.Byte_Array[k];
                *(tmp_char + (399 - j) * sizeof(WORD) + k) =   Swap_16.Byte_Array[k];
                *(tmp_char + (100 + j) * sizeof(WORD) + k) = Scaled_16.Byte_Array[k];
                *(tmp_char + (299 - j) * sizeof(WORD) + k) = Scaled_16.Byte_Array[k];
            } /* end for (k... */
        } /* end for (j... */

        Swap_16.Short_Int = 0xFFFE;
        Swap_16.Short_Int = ipc_word_swap (Swap_16.Short_Int);
        for (k = 0;k < sizeof(WORD);k++) // now store them and mirrored versions
        {
            *(tmp_char + 100 * sizeof(WORD) + k) = Swap_16.Byte_Array[k];
            *(tmp_char + 299 * sizeof(WORD) + k) = Swap_16.Byte_Array[k];
        }

        tmp_char += 800; /* account for the indexing of the copied data */
    } /* end for (i... */
}               
#pragma optimize( "lge", on )
/****************************************************************************
*                          <<< Code Block >>>                               *
*                                                                           *
*   Function Name: BuildTraceEch                                            *
*                                                                           *
*   Description: Build trace curve for simulation of results data return.   *
*                                                                           *
*   Inputs:                                                                 *
*      Arguments:                                                           *
*         Curve        trace slot (number) to build.                        *
*         ReturnBuff   structure which contains data stream and attributes. *
*      Global:                                                              *
*                                                                           *
*   Outputs:                                                                *
*      N/A                                                                  *
*                                                                           *
****************************************************************************/
void BuildTraceEch (int Slot,IPC_msg_t *ReturnBuff)
{
    unsigned char *tmp_char;                 /* buffer pointer */
    int i,j,k;
    Type_32_Bits Swap_32;
    Type_16_Bits Swap_16;
    Type_16_Bits Scaled_16;

    ReturnBuff->byte_cnt = (1 + 1 + 1 + 1+ 4 + 9 * (2 + 2 + 4 + 100 * 3 * 2));

    tmp_char = ReturnBuff->data_ptr;

    *(tmp_char++) = TESTRES_ECHEM;
    *(tmp_char++) = (UCHAR)Slot; /* put slot number here */

    *(tmp_char++) = 0x01;         /* indicate trace data */
    *(tmp_char++) = 0x0;

    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;

    for (i = 0;i < 9;i++) /* 9 trace points for now */
    {
        *(tmp_char++) = (UCHAR)(0xff);   /* separator */
        *(tmp_char++) = (UCHAR)(0xff);

        *(tmp_char++) = 0x0;
        *(tmp_char++) = DAT_ECHEM_STATE1 + i;

        Swap_32.Long_Int = 60000;     /* get current rtp time */
        Swap_32.Long_Int = ipc_long_swap(Swap_32.Long_Int);

        for (j = 0;j < sizeof(DWORD);j++) /* store rtp time */
            *(tmp_char++) = Swap_32.Byte_Array[j];

        for (j = 0;j < 100;j++) /* loop thru first 100 raw a/d counts */
        {
            /*
            ** calculate full and scaled values
            */
              Swap_32.Floating_Point  = (float)j;
              Swap_32.Floating_Point *= 0.6464f;
              Swap_32.Floating_Point  =
                Swap_32.Floating_Point * Swap_32.Floating_Point;
              Swap_16.Short_Int       = (WORD)(Swap_32.Floating_Point);
            Scaled_16.Short_Int       = 4095 - Swap_16.Short_Int / 16;

            /*
            ** now swap them
            */
              Swap_16.Short_Int = ipc_word_swap(  Swap_16.Short_Int);
            Scaled_16.Short_Int = ipc_word_swap(Scaled_16.Short_Int);

            for (k = 0;k < sizeof(WORD);k++) /* now store them */
            {
                *(tmp_char + (  0 + j) * sizeof(WORD) + k) =   Swap_16.Byte_Array[k];
                *(tmp_char + (100 + j) * sizeof(WORD) + k) = Scaled_16.Byte_Array[k];
                *(tmp_char + (299 - j) * sizeof(WORD) + k) =   Swap_16.Byte_Array[k];
            } /* end for (k... */
        } /* end for (j... */

        tmp_char += 600; /* account for the indexing of the copied data */
    } /* end for (i... */
}               

/****************************************************************************
*                          <<< Code Block >>>                               *
*                                                                           *
*   Function Name: BuildTraceCoag                                           *
*                                                                           *
*   Description: Build trace curve for simulation of results data return.   *
*                                                                           *
*   Inputs:                                                                 *
*      Arguments:                                                           *
*         Curve        trace slot (number) to build.                        *
*         ReturnBuff   structure which contains data stream and attributes. *
*      Global:                                                              *
*                                                                           *
*   Outputs:                                                                *
*      N/A                                                                  *
*                                                                           *
****************************************************************************/
void BuildTraceCoag (int Slot,IPC_msg_t *ReturnBuff)
{
    unsigned char *tmp_char;                 /* buffer pointer */
    int i,j,k;
    Type_32_Bits Swap_32;
    Type_16_Bits Swap_16;
    Type_16_Bits Scaled_16;

    ReturnBuff->byte_cnt = (1 + 1 + 1 + 1 + 4 + 3 * (2 + 4 + 100 * 3 * 2));

    tmp_char = ReturnBuff->data_ptr;

    *(tmp_char++) = TESTRES_COAG;
    *(tmp_char++) = (UCHAR)Slot; /* put slot number here */

    *(tmp_char++) = 0x01;         /* indicate trace data */
    *(tmp_char++) = 0x0;

    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;

    for (i = 0;i < 3;i++) /* 3 trace points for now */
    {
        *(tmp_char++) = (UCHAR)(0xff);   /* separator */
        *(tmp_char++) = (UCHAR)(0xff);

        Swap_32.Long_Int = 60000;     /* get current rtp time */
        Swap_32.Long_Int = ipc_long_swap(Swap_32.Long_Int);

        for (j = 0;j < sizeof(DWORD);j++) /* store rtp time */
            *(tmp_char++) = Swap_32.Byte_Array[j];

        for (j = 0;j < 100;j++) /* loop thru first 100 raw a/d counts */
        {
            /*
            ** calculate full and scaled values
            */
              Swap_32.Floating_Point  = (float)j;
              Swap_32.Floating_Point *= 0.6464f;
              Swap_32.Floating_Point  =
                Swap_32.Floating_Point * Swap_32.Floating_Point;
              Swap_16.Short_Int       = (WORD)(Swap_32.Floating_Point);
            Scaled_16.Short_Int       = 4095 - Swap_16.Short_Int / 16;

            /*
            ** now swap them
            */
              Swap_16.Short_Int = ipc_word_swap(  Swap_16.Short_Int);
            Scaled_16.Short_Int = ipc_word_swap(Scaled_16.Short_Int);

            for (k = 0;k < sizeof(WORD);k++) /* now store them */
            {
                *(tmp_char + (  0 + j) * sizeof(WORD) + k) =   Swap_16.Byte_Array[k];
                *(tmp_char + (100 + j) * sizeof(WORD) + k) = Scaled_16.Byte_Array[k];
                *(tmp_char + (299 - j) * sizeof(WORD) + k) =   Swap_16.Byte_Array[k];
            } /* end for (k... */
        } /* end for (j... */

        tmp_char += 600; /* account for the indexing of the copied data */
    } /* end for (i... */
}               

/****************************************************************************
*                          <<< Code Block >>>                               *
*                                                                           *
*   Function Name: BuildStandard                                            *
*                                                                           *
*   Description: Build standard curve for simulation of results data return.*
*                                                                           *
*   Inputs:                                                                 *
*      Arguments:                                                           *
*         Curve        standard curve (number) to build.                    *
*         ReturnBuff   structure which contains data stream and attributes. *
*      Global:                                                              *
*         RTP_TIME_INC determines platter wide time increment for tests.    *
*                                                                           *
*   Outputs:                                                                *
*      N/A                                                                  *
*                                                                           *
****************************************************************************/
void BuildStandard (int Curve,IPC_msg_t *ReturnBuff)
{
    DWORD           RTP_Time;
    unsigned char   *tmp_char;  /* buffer pointer */
    int             i,j;
    int             num_dp;
    Type_32_Bits    Root_32;
    Type_32_Bits    Square_32;
    Type_32_Bits    Swap_32;

    RTP_Time = 4000L;


    if (!IQC_Platter)
    {
        /*
         * byte_cnt =
         *  Technology type     1
         *  Curve #             1
         *  Progression curve   1
         *  LED Number          1
         *  Delta Time          4
         *  # of data points    MAX_REDUCED_ENTRIES * x
         *      where x is the sum of =
         *          Max A/D counts      2
         *          # of conversions    2
         *          timestamp           4
         *          running average     4
         *          running sqd average 4
         */
        ReturnBuff->byte_cnt = 1992;
        tmp_char = ReturnBuff->data_ptr;
        /* 08/31/99 SEP mah, modified for lead-lag photo-diodes */
        num_dp = MAX_REDUCED_ENTRIES;

        *(tmp_char++) = TESTRES_FILM;   /* Technology type */   }
    else
    {
        /*
         * byte_cnt =
         *  Technology type     1
         *  Curve #             1
         *  Progression curve   1
         *  LED Number          1
         *  Delta Time          4
         *  # of data points    8 * x
         *      where x is the sum of =
         *          Max A/D counts      2
         *          # of conversions    2
         *          timestamp           4
         *          running average     4
         *          running sqd average 4
         */
        ReturnBuff->byte_cnt = 136;
        tmp_char = ReturnBuff->data_ptr;
        num_dp = 8;

        *(tmp_char++) = TESTRES_FILM ;  /* Technology type */
    }

    *(tmp_char++) = (UCHAR)Curve;   /* put curve number here */
    *(tmp_char++) = 0x00;           /* Progression Curve */
    *(tmp_char++) = 0x00;           /* LED Number - 0 for standards */

    *(tmp_char++) = 0x00;           /* fill in 0 for standards delta time */
    *(tmp_char++) = 0x00;
    *(tmp_char++) = 0x00;
    *(tmp_char++) = 0x00;                      
    
    if (Curve >= 14 && Curve < 21)
      Curve -= 7; // want identical results for led's ws1 and ws2
      
    Root_32.Floating_Point  = (float)(34 - Curve);  /* curve dependent */
    if (Root_32.Floating_Point < 14)
      Root_32.Floating_Point *= 45.0f;
    else
      Root_32.Floating_Point *= 151.0f;               /* scale for near full scale */

    Square_32.Floating_Point  = Root_32.Floating_Point; /* setup for square */
    Square_32.Floating_Point  = (Square_32.Floating_Point * Square_32.Floating_Point);  /* square it */

    Root_32.Long_Int = ipc_long_swap(Root_32.Long_Int);
    Square_32.Long_Int = ipc_long_swap(Square_32.Long_Int);

    /* 08/31/99 SEP mah, modified for lead-lag photo-diodes */
    for (i=0; i<num_dp; i++) /* MAX_REDUCED_ENTRIES (normal), 8(IQC) points */
    {
        *(tmp_char++) = 0x00;      /* lagging_count, i for now */
        *(tmp_char++) = (UCHAR)i % 2;

        *(tmp_char++) = 0x01;     /* number of conversions, 400 */
        *(tmp_char++) = 0x090;

        Swap_32.Long_Int = RTP_Time;     /* get current rtp time */
        Swap_32.Long_Int = ipc_long_swap(Swap_32.Long_Int);

        for (j = 0;j < sizeof(DWORD);j++) /* store rtp time */
            *(tmp_char++) = Swap_32.Byte_Array[j];

        RTP_Time += RTP_TIME_INC;         /* increment rtp time */

        for (j = 0;j < sizeof(DWORD);j++,tmp_char++) /* now store the root and square */
        {
            *(tmp_char + 0) =   Root_32.Byte_Array[j];
            *(tmp_char + 4) = Square_32.Byte_Array[j];
        }

        tmp_char += 4; /* update index for squared value */
    } /* end for (i... */
}               

/****************************************************************************
*                          <<< Code Block >>>                               *
*                                                                           *
*   Function Name: BuildTestCurve                                           *
*                                                                           *
*   Description: Build test curve for simulation of results data return.    *
*                                                                           *
*   Inputs:                                                                 *
*      Arguments:                                                           *
*         Curve        test curve (number) to build.                        *
*         ReturnBuff   structure which contains data stream and attributes. *
*      Global:                                                              *
*         RTP_TIME_INC determines platter wide time increment for tests.    *
*                                                                           *
*   Outputs:                                                                *
*      N/A                                                                  *
*                                                                           *
****************************************************************************/
void BuildTestCurve (int Curve,IPC_msg_t *ReturnBuff)
{
    DWORD RTP_Time;
    unsigned char *tmp_char;                 /* buffer pointer */
    int i,j;
    Type_32_Bits Root_32;
    Type_32_Bits Square_32;
    Type_32_Bits Swap_32;

    RTP_Time = 4000L;

    /* 08/31/99 SEP mah, modified for lead-lag photo-diodes */
    ReturnBuff->byte_cnt = (1 + 1 + 1 + 1 + 4 + 
                                     MAX_REDUCED_ENTRIES * (2 + 2 + 4 + 4 + 4));

    tmp_char = ReturnBuff->data_ptr;

    *(tmp_char++) = TESTRES_FILM;
    *(tmp_char++) = (UCHAR)Curve; /* put curve number here */
    *(tmp_char++) = 0x0;             /* indicate not trace data */
    *(tmp_char++) = 0x0;

  switch(Curve)
  {
    case 1:
      *(tmp_char++) = 0x00; /* delta_time = 0msec */
      *(tmp_char++) = 0x00;
      *(tmp_char++) = 0x00;
      *(tmp_char++) = 0x00;
      break;
    case 2:
      *(tmp_char++) = 0x00; /* delta_time = 25375msec */
      *(tmp_char++) = 0x00;
      *(tmp_char++) = 0x63;
      *(tmp_char++) = 0x1f;
      break;
    case 3:
      *(tmp_char++) = 0x00; /* delta_time = 50750msec */
      *(tmp_char++) = 0x00;
      *(tmp_char++) = 0xc6;
      *(tmp_char++) = 0x3e;
      break;
    case 4:
      *(tmp_char++) = 0x00; /* delta_time = 76125msec */
      *(tmp_char++) = 0x01;
      *(tmp_char++) = 0x29;
      *(tmp_char++) = 0x5d;
      break;
    case 5:
      *(tmp_char++) = 0x00; /* delta_time = 101500msec */
      *(tmp_char++) = 0x01;
      *(tmp_char++) = 0x8c;
      *(tmp_char++) = 0x7c;
      break;
    case 6:
      *(tmp_char++) = 0x00; /* delta_time = 126875msec */
      *(tmp_char++) = 0x01;
      *(tmp_char++) = 0xef;
      *(tmp_char++) = 0x9b;
      break;
    default:
      *(tmp_char++) = 0x00; /* delta_time = 0msec */
      *(tmp_char++) = 0x00;
      *(tmp_char++) = 0x00;
      *(tmp_char++) = 0x00;
      break;
  }
            
    /* 08/31/99 SEP mah, modified for lead-lag photo-diodes */
    for (i = 0;i < MAX_REDUCED_ENTRIES;i++) /* MAX_REDUCED_ENTRIES points */
    {
        *(tmp_char++) = 0x00;      /* lagging_count, i for now */
        *(tmp_char++) = (UCHAR)i % 2;

        *(tmp_char++) = 0x01;     /* number of conversions, 400 */
        *(tmp_char++) = 0x090;

        Swap_32.Long_Int = RTP_Time;     /* get current rtp time */
        Swap_32.Long_Int = ipc_long_swap(Swap_32.Long_Int);

        for (j = 0;j < sizeof(DWORD);j++) /* store rtp time */
            *(tmp_char++) = Swap_32.Byte_Array[j];

        RTP_Time += RTP_TIME_INC;         /* increment rtp time */

        /*
        ** aim at an ellipse
        */
        Square_32.Floating_Point  = (float)i;    /* start with current x */
        Square_32.Floating_Point -= 52.0f;       /* subtract for center */
        Square_32.Floating_Point *= 58.75f;      /* scale for unequal axis */
        Square_32.Floating_Point  =              /* square it */
            Square_32.Floating_Point * Square_32.Floating_Point;
        Square_32.Floating_Point *= -1.0f;       /* make it negative */
        Square_32.Floating_Point += 4269025.0f; /* add square of hypot */
        if (Square_32.Floating_Point <= 0)
        {
          Root_32.Floating_Point = (float) 500.0f;
        }
        else
        {
      Root_32.Floating_Point  =
        (float)sqrt ((double)Square_32.Floating_Point); /* = y */
    }
    if (Root_32.Floating_Point < 500)
      Root_32.Floating_Point = 500;

        Root_32.Long_Int = ipc_long_swap(  Root_32.Long_Int);
        Square_32.Long_Int = ipc_long_swap(Square_32.Long_Int);

        for (j = 0;j < sizeof(DWORD);j++,tmp_char++) /* now store the root and square */
        {
            *(tmp_char + 0) =   Root_32.Byte_Array[j];
            *(tmp_char + 4) = Square_32.Byte_Array[j];
        }

        tmp_char += 4; /* update index for squared value */
    } /* end for (i... */
}               

/* dwj added function */
/****************************************************************************
*                          <<< Code Block >>>                               *
*                                                                           *
*   Function Name: BuildTestCurveEch                                        *
*                                                                           *
*   Description: Build test curve for simulation of results data return.    *
*                                                                           *
*   Inputs:                                                                 *
*      Arguments:                                                           *
*         Curve        test curve (number) to build.                        *
*         ReturnBuff   structure which contains data stream and attributes. *
*      Global:                                                              *
*         RTP_TIME_INC determines platter wide time increment for tests.    *
*                                                                           *
*   Outputs:                                                                *
*      N/A                                                                  *
*                                                                           *
****************************************************************************/
void BuildTestCurveEch (int Curve,IPC_msg_t *ReturnBuff)
{
    unsigned char *tmp_char;                 /* buffer pointer */
    int i,j;
    Type_32_Bits Root_32;
    Type_32_Bits Square_32;
    Type_32_Bits Swap_32;
    static int time[15] = {30,30,30,45,45,45,60,60,60,60,60,60,60,60,60};
    static int relay[15] = {DAT_ECHEM_STATE4,DAT_ECHEM_STATE6,DAT_ECHEM_STATE8,
        DAT_ECHEM_STATE4,DAT_ECHEM_STATE6,DAT_ECHEM_STATE8,
        DAT_ECHEM_STATE4,DAT_ECHEM_STATE6,DAT_ECHEM_STATE8,
        DAT_ECHEM_STATE5,DAT_ECHEM_STATE7,DAT_ECHEM_STATE9,
        DAT_ECHEM_STATE1,DAT_ECHEM_STATE2,DAT_ECHEM_STATE3};
    static int value[15] = {2053,2045,2045,2053,2045,2045,
        2053,2045,2045,2047,2042,2042,2046,2041,2040};

    ReturnBuff->byte_cnt = (1 + 1 + 1 + 1 + 4 + 15 * (2 + 2 + 2 + 4 + 4 + 4));

    tmp_char = ReturnBuff->data_ptr;

    *(tmp_char++) = TESTRES_ECHEM;
    *(tmp_char++) = (UCHAR)Curve; /* put curve number here */
    *(tmp_char++) = 0x0;             /* indicate not trace data */
    *(tmp_char++) = 0x0;

    *(tmp_char++) = 0x0;             /* fill in 0 for standards delta time */
    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;

    for (i = 0;i < 15;i++) /* 15 data points for now */
    {
        *(tmp_char++) = 0x0;
        *(tmp_char++) = relay[i];

        *(tmp_char++) = 0x0;      /* max a2d counts, i for now */
        *(tmp_char++) = (UCHAR)i;

        *(tmp_char++) = 0x01;     /* number of conversions, 400 */
        *(tmp_char++) = 0x090;

        Swap_32.Long_Int = time[i] * 1000L;
        Swap_32.Long_Int = ipc_long_swap(Swap_32.Long_Int);

        for (j = 0;j < sizeof(DWORD);j++) /* store rtp time */
            *(tmp_char++) = Swap_32.Byte_Array[j];

        /*
        ** constant value
        */
        Root_32.Floating_Point  = (float)value[i];
        Square_32.Floating_Point =
            Root_32.Floating_Point * Root_32.Floating_Point;

          Root_32.Long_Int = ipc_long_swap(  Root_32.Long_Int);
        Square_32.Long_Int = ipc_long_swap(Square_32.Long_Int);

        for (j = 0;j < sizeof(DWORD);j++,tmp_char++) /* now store the root and square */
        {
            *(tmp_char + 0) =   Root_32.Byte_Array[j];
            *(tmp_char + 4) = Square_32.Byte_Array[j];
        }

        tmp_char += 4; /* update index for squared value */
    } /* end for (i... */
}               

/****************************************************************************
*                          <<< Code Block >>>                               *
*                                                                           *
*   Function Name: BuildTestCurveCoag                                       *
*                                                                           *
*   Description: Build test curve for simulation of results data return.    *
*                                                                           *
*   Inputs:                                                                 *
*      Arguments:                                                           *
*         Curve        test curve (number) to build.                        *
*         ReturnBuff   structure which contains data stream and attributes. *
*      Global:                                                              *
*         RTP_TIME_INC determines platter wide time increment for tests.    *
*                                                                           *
*   Outputs:                                                                *
*      N/A                                                                  *
*                                                                           *
****************************************************************************/
void BuildTestCurveCoag (int Curve,IPC_msg_t *ReturnBuff)
{
    DWORD RTP_Time;
    unsigned char *tmp_char;                 /* buffer pointer */
    int i,j;
    Type_32_Bits Value_32;
    Type_32_Bits Log_32;
    Type_32_Bits Swap_32;

    RTP_Time = 4000L;

    ReturnBuff->byte_cnt = (1 + 1 + 1 + 1 + 4 + 300 * (4 + 4));

    tmp_char = ReturnBuff->data_ptr;

    *(tmp_char++) = TESTRES_COAG;
    *(tmp_char++) = (UCHAR)Curve; /* put curve number here */
    *(tmp_char++) = 0x0;             /* indicate not trace data */
    *(tmp_char++) = 0x0;

    *(tmp_char++) = 0x0;             /* fill in 0 for standards delta time */
    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;

    for (i = 0;i < 300;i++) /* 300 data points for now */
    {
        Swap_32.Long_Int = RTP_Time;     /* get current rtp time */
        Swap_32.Long_Int = ipc_long_swap(Swap_32.Long_Int);

        for (j = 0;j < sizeof(DWORD);j++) /* store rtp time */
            *(tmp_char++) = Swap_32.Byte_Array[j];

        RTP_Time += 50;         /* increment rtp time */

        if (i < 100)
        {
            Value_32.Floating_Point = (float) 3025;
        }
        else
        {
            if (i > 185)
            {
                Value_32.Floating_Point = (float) 30;
            }
            else
            {
                Log_32.Floating_Point = (float) (i - 100);
                Log_32.Floating_Point /= (float) 34.0;
                Log_32.Floating_Point *= Log_32.Floating_Point;
                Value_32.Floating_Point = (float) exp (-Log_32.Floating_Point);
                Value_32.Floating_Point *= (float) 3000.0;
                Value_32.Floating_Point += (float) 25.0;
            }
        }

        Value_32.Long_Int = ipc_long_swap(  Value_32.Long_Int);

        for (j = 0;j < sizeof(DWORD);j++,tmp_char++) /* now store the root and square */
        {
            *(tmp_char + 0) =   Value_32.Byte_Array[j];
        }
    } /* end for (i... */
}               

/***************************************************************************
* then later after the function to re-enable them.                         *
*                                                                          *
* pragma letter compiler option description                                *
* ============= =============== ========================================== *
* e             /Oe             Set global register allocation.            *
*                                                                          *
* g             /Og             Perform global common subexpression        *
*                               optimization. This option is effective     *
*                               only with the optimizing code generator.   *
*                                                                          *
* l             /Ol             Perform loop code optimization.            *
*                                                                          *
***************************************************************************/
#pragma optimize( "lge", off )

/****************************************************************************
*                          <<< Code Block >>>                               *
*                                                                           *
*   Function Name: BuildTestCurveIQC                                        *
*                                                                           *
*   Description: Build test curve for simulation of results data return.    *
*                                                                           *
*   Inputs:                                                                 *
*      Arguments:                                                           *
*         Curve        test curve (number) to build.                        *
*         ReturnBuff   structure which contains data stream and attributes. *
*      Global:                                                              *
*         RTP_TIME_INC determines platter wide time increment for tests.    *
*                                                                           *
*   Outputs:                                                                *
*      N/A                                                                  *
*                                                                           *
****************************************************************************/
void BuildTestCurveIQC (Cart_Options_e carttype, int Curve, BYTE led_num, IPC_msg_t *ReturnBuff)
{
    DWORD RTP_Time;
    unsigned char *tmp_char;                 /* buffer pointer */
    int i,j;
    Type_32_Bits Root_32;
    Type_32_Bits Square_32;
    Type_32_Bits Swap_32;
    static int time[15] = {30,30,30,45,45,45,60,60,60,60,60,60,60,60,60};
    static int relay[15] = {DAT_ECHEM_STATE4,DAT_ECHEM_STATE6,DAT_ECHEM_STATE8,
        DAT_ECHEM_STATE4,DAT_ECHEM_STATE6,DAT_ECHEM_STATE8,
        DAT_ECHEM_STATE4,DAT_ECHEM_STATE6,DAT_ECHEM_STATE8,
        DAT_ECHEM_STATE5,DAT_ECHEM_STATE7,DAT_ECHEM_STATE9,
        DAT_ECHEM_STATE1,DAT_ECHEM_STATE2,DAT_ECHEM_STATE3};
    static int value[15] = {2053,2045,2045,2053,2045,2045,
        2053,2045,2045,2047,2042,2042,2046,2041,2040};

    switch (carttype)
    {
        case CART_FILM_TYPE:

            RTP_Time = 4000L;
            /*
             * byte_cnt =
             *  Technology type     1
             *  Curve #             1
             *  Progression curve   1
             *  LED Number          1
             *  Delta Time          4
             *  # of data points    8 * x
             *      where x is the sum of =
             *          Max A/D counts      2
             *          # of conversions    2
             *          timestamp           4
             *          running average     4
             *          running sqd average 4
             */
            ReturnBuff->byte_cnt = 136;

            tmp_char = ReturnBuff->data_ptr;

            *(tmp_char++) = TESTRES_FILM;
            *(tmp_char++) = (UCHAR)Curve;   /* put curve number here */
            *(tmp_char++) = 0x00;           /* indicate not trace data */
            *(tmp_char++) = led_num;        /* LED number */

            *(tmp_char++) = 0x00;           /* fill in 0 for standards delta time */
            *(tmp_char++) = 0x00;
            *(tmp_char++) = 0x00;
            *(tmp_char++) = 0x00;

            for (i=0; i<8; i++) /* 8 data points for now */
            {
                /* 08/31/99 SEP mah, modified for lead-lag photo-diodes */
                *(tmp_char++) = 0x00;       /* lagging_count, 1005 for now */
                *(tmp_char++) = (UCHAR)i % 2;

                *(tmp_char++) = 0x00;       /* # of conversions, 150 for now */
                *(tmp_char++) = 0x96;

                Swap_32.Long_Int = RTP_Time;     /* get current rtp time */
                Swap_32.Long_Int = ipc_long_swap(Swap_32.Long_Int);

                for (j=0; j<sizeof(DWORD); j++) /* store rtp time */
                    *(tmp_char++) = Swap_32.Byte_Array[j];

                RTP_Time += RTP_TIME_INC;         /* increment rtp time */

                Root_32.Floating_Point = 997.56f + ((float)(3*led_num));
                Square_32.Floating_Point = (Root_32.Floating_Point * Root_32.Floating_Point);
        
                Root_32.Long_Int = ipc_long_swap(Root_32.Long_Int);
                Square_32.Long_Int = ipc_long_swap(Square_32.Long_Int);
        
                for (j=0; j<sizeof(DWORD); j++,tmp_char++) /* now store the root and square */
                {
                    *(tmp_char + 0) =   Root_32.Byte_Array[j];
                    *(tmp_char + 4) = Square_32.Byte_Array[j];
                }

                tmp_char += 4; /* update index for squared value */
            } /* end for (i... */

            break;
            
        case CART_ECH_TYPE:
            /*
             * byte_cnt =
             *  Technology type     1
             *  Curve #             1
             *  Progression curve   1
             *  LED Number          1
             *  Delta Time          4
             *  # of data points    15 * x
             *      where x is the sum of =
             *          Relay State         2
             *          Max A/D counts      2
             *          # of conversions    2
             *          timestamp           4
             *          running average     4
             *          running sqd average 4
             */
            ReturnBuff->byte_cnt = 278;

            tmp_char = ReturnBuff->data_ptr;

            *(tmp_char++) = TESTRES_ECHEM;
            *(tmp_char++) = (UCHAR)Curve; /* put curve number here */
            *(tmp_char++) = 0x00;             /* indicate not trace data */
            *(tmp_char++) = 0x00;

            *(tmp_char++) = 0x00;             /* fill in 0 for standards delta time */
            *(tmp_char++) = 0x00;
            *(tmp_char++) = 0x00;
            *(tmp_char++) = 0x00;

            for (i=0; i<15; i++) /* 15 data points for now */
            {
                *(tmp_char++) = 0x00;
                *(tmp_char++) = relay[i];
        
                *(tmp_char++) = 0x00;      /* max a2d counts, i for now */
                *(tmp_char++) = (UCHAR)i;
        
                *(tmp_char++) = 0x01;     /* number of conversions, 400 */
                *(tmp_char++) = 0x090;
        
                Swap_32.Long_Int = time[i] * 1000L;
                Swap_32.Long_Int = ipc_long_swap(Swap_32.Long_Int);
        
                for (j = 0;j < sizeof(DWORD);j++) /* store rtp time */
                    *(tmp_char++) = Swap_32.Byte_Array[j];
        
                /*
                 * constant value
                 */
                Root_32.Floating_Point  = (float)value[i];
                Square_32.Floating_Point = Root_32.Floating_Point * Root_32.Floating_Point;
        
                Root_32.Long_Int = ipc_long_swap(Root_32.Long_Int);
                Square_32.Long_Int = ipc_long_swap(Square_32.Long_Int);
        
                for (j = 0;j < sizeof(DWORD);j++,tmp_char++) /* now store the root and square */
                {
                    *(tmp_char + 0) = Root_32.Byte_Array[j];
                    *(tmp_char + 4) = Square_32.Byte_Array[j];
                }
        
                tmp_char += 4; /* update index for squared value */
            } /* end for (i... */

            break;
        
        case CART_COAG_TYPE:
            RTP_Time = 50L;
            /*
             * byte_cnt =
             *  Technology type     1
             *  Curve #             1
             *  Progression curve   1
             *  LED Number          1
             *  Delta Time          4
             *  # of data points    200 * x
             *      where x is the sum of =
             *          timestamp           4
             *          running average     4
             */
            ReturnBuff->byte_cnt = 1608;

            tmp_char = ReturnBuff->data_ptr;

            *(tmp_char++) = TESTRES_COAG;
            *(tmp_char++) = (UCHAR)Curve;   /* put curve number here */
            *(tmp_char++) = 0x00;           /* indicate not trace data */
            *(tmp_char++) = 0x00;

            *(tmp_char++) = 0x00;           /* fill in 0 for standards delta time */
            *(tmp_char++) = 0x00;
            *(tmp_char++) = 0x00;
            *(tmp_char++) = 0x00;

            for (i=0; i<200; i++) /* 200 data points (10secs x 50msec/dp) for now */
            {
                Swap_32.Long_Int = RTP_Time;     /* get current rtp time */
                Swap_32.Long_Int = ipc_long_swap(Swap_32.Long_Int);

                for (j=0; j<sizeof(DWORD); j++) /* store rtp time */
                    *(tmp_char++) = Swap_32.Byte_Array[j];

                RTP_Time += 50;         /* increment rtp time */

                Root_32.Floating_Point = 877.43f;
                
                Root_32.Long_Int = ipc_long_swap(Root_32.Long_Int);
                
                for (j=0; j<sizeof(DWORD); j++,tmp_char++)  /* now store the root & square */
                    *(tmp_char+0) = Root_32.Byte_Array[j];
            } /* end for i */
            
            break;
                    
        default:
            break;
    }
}               

#pragma optimize( "lge", on )

/****************************************************************************
*                          <<< Code Block >>>                               *
*                                                                           *
*   Function Name: BuildDryFilm                                             *
*                                                                           *
*   Description: Build test curve for simulation of results data return.    *
*                                                                           *
*   Inputs:                                                                 *
*      Arguments:                                                           *
*         Curve        test curve (number) to build.                        *
*         ReturnBuff   structure which contains data stream and attributes. *
*      Global:                                                              *
*         RTP_TIME_INC determines platter wide time increment for tests.    *
*                                                                           *
*   Outputs:                                                                *
*      N/A                                                                  *
*                                                                           *
****************************************************************************/
void BuildDryFilm (int Curve,IPC_msg_t *ReturnBuff)
{
    DWORD RTP_Time;
    unsigned char *tmp_char;                 /* buffer pointer */
    int i;
    int j;
    Type_32_Bits Root_32;
    Type_32_Bits Square_32;
    Type_32_Bits Swap_32;

    RTP_Time = 0L;

    ReturnBuff->byte_cnt = (1 + 1 + 1 + 1 + 4 + 2 * (2 + 2 + 4 + 4 + 4));

    tmp_char = ReturnBuff->data_ptr;

    *(tmp_char++) = TESTRES_FILM;
    *(tmp_char++) = (UCHAR)Curve; /* put curve number here */
    *(tmp_char++) = 0x2;             /* indicate not trace data */
    *(tmp_char++) = 0x0;

    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;

    for( i = 0; i < 2; i++) /* 1 data point for now */
    {
        /* 08/31/99 SEP mah, modified for lead-lag photo-diodes */
        *(tmp_char++) = 0x00;      /* lagging_count, i for now */
        *(tmp_char++) = (UCHAR)i % 2;

        *(tmp_char++) = 0x01;     /* number of conversions, 400 */
        *(tmp_char++) = 0x090;

        Swap_32.Long_Int = RTP_Time;     /* get current rtp time */
        Swap_32.Long_Int = ipc_long_swap(Swap_32.Long_Int);

        for (j = 0;j < sizeof(DWORD);j++) /* store rtp time */
            *(tmp_char++) = Swap_32.Byte_Array[j];

        RTP_Time += RTP_TIME_INC;         /* increment rtp time */

        if (Curve >= (BYTE)LED1_DAT_W1_STAND)
        {
            Root_32.Floating_Point  = (float)(34 - Curve); /* curve dependent */
            Root_32.Floating_Point *= 151.0f;       /* scale for near full scale */
        }
        else
        {
            Root_32.Floating_Point  = 2048.0f;
        }
        Square_32.Floating_Point  = Root_32.Floating_Point; /* setup for square */
        Square_32.Floating_Point  =               /* square it */
            Square_32.Floating_Point * Square_32.Floating_Point;
        Root_32.Long_Int = ipc_long_swap(  Root_32.Long_Int);
        Square_32.Long_Int = ipc_long_swap(Square_32.Long_Int);

        for (j = 0;j < sizeof(DWORD);j++,tmp_char++) /* now store the root and square */
        {
            *(tmp_char + 0) =   Root_32.Byte_Array[j];
            *(tmp_char + 4) = Square_32.Byte_Array[j];
        }

        tmp_char += 4; /* update index for squared value */
    } /* end for (i... */
}               

/****************************************************************************
*                          <<< Code Block >>>                               *
*                                                                           *
*   Function Name: BuildDryCoag                                             *
*                                                                           *
*   Description: Build test curve for simulation of results data return.    *
*                                                                           *
*   Inputs:                                                                 *
*      Arguments:                                                           *
*         Curve        test curve (number) to build.                        *
*         ReturnBuff   structure which contains data stream and attributes. *
*      Global:                                                              *
*         RTP_TIME_INC determines platter wide time increment for tests.    *
*                                                                           *
*   Outputs:                                                                *
*      N/A                                                                  *
*                                                                           *
****************************************************************************/
void BuildDryCoag (int Curve,IPC_msg_t *ReturnBuff)
{
    DWORD RTP_Time;
    unsigned char *tmp_char;                 /* buffer pointer */
    int i,j;
    Type_32_Bits Value_32;
    Type_32_Bits Swap_32;

    RTP_Time = 0L;

    ReturnBuff->byte_cnt = (1 + 1 + 1 + 1 + 4 + 2 * (4 + 4));

    tmp_char = ReturnBuff->data_ptr;

    *(tmp_char++) = TESTRES_COAG;
    *(tmp_char++) = (UCHAR)Curve; /* put curve number here */
    *(tmp_char++) = 0x2;             /* indicate not trace data */
    *(tmp_char++) = 0x0;

    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;
    *(tmp_char++) = 0x0;

    for (i = 0;i < 2;i++) /* 2 data points for now */
    {
        Swap_32.Long_Int = RTP_Time;     /* get current rtp time */
        Swap_32.Long_Int = ipc_long_swap(Swap_32.Long_Int);

        for (j = 0;j < sizeof(DWORD);j++) /* store rtp time */
            *(tmp_char++) = Swap_32.Byte_Array[j];

        RTP_Time += 50;         /* increment rtp time */

        Value_32.Floating_Point = (float) (i ? 3156 : 25);

          Value_32.Long_Int = ipc_long_swap(  Value_32.Long_Int);

        for (j = 0;j < sizeof(DWORD);j++,tmp_char++) /* now store the root and square */
        {
            *(tmp_char + 0) =   Value_32.Byte_Array[j];
        }
    } /* end for (i... */
}               

/****************************************************************************
*                          <<< Code Block >>>                               *
*                                                                           *
*   Function Name: Build_IPC_Msg                                            *
*                                                                           *
*   Description:                                                            *
*                                                                           *
*   Inputs:                                                                 *
*                                                                           *
*   Outputs:                                                                *
****************************************************************************/
void ipc_build_msg(BYTE Message_Id, UINT Byte_Count, BYTE *Ptr)
{
    Message_Id = Message_Id;
    Byte_Count = Byte_Count;
    Ptr = Ptr;
    
}  /* end of Build_IPC_Msg */


//============================================================================
//                              Create_Cartridge
//
// Description: creates the 36 byte barcode label pattern for a cartridge with
//      the given parameters
//  
// Inputs: 
//    id    = cartridge id (eg: 600 for echem)
//    day   = exp. day of month (1-31)
//    month = exp. month of year (1-12)
//    year  = exp. year (1970 - 2225)
//    lot   = lot number
//    
//
// Outputs: 
//    return_data = pointer to buffer to hold barcode label 
//
// Returns: None
//
//
//----------------------------------------------------------------------------
void Create_Cartridge(long id, long month, long day, long year, long lot,
                      IPC_msg_t* return_data)
  {
  int i;
  unsigned short checksum;
  unsigned char *byte_ptr;
  unsigned long  stripes[9]; 
  
  
  
  return_data->ID = (int)MSG_BARCODE_RESULTS;
  return_data->byte_cnt = 38;  
  
  
  // first byte in returned stream is slot #1-6
//  CSB fixed to match RTP return value.
//  return_data->data_ptr[0] = (UCHAR)db_get_num_inserted_carts()+1;
  return_data->data_ptr[0] = platter_slot[db_get_num_inserted_carts()];
                  
  // For a film cart....
                  
  // Stripes 1 and 2 are all-zero (AZ)
  stripes[0] = 0L;
  stripes[1] = 0L;
                                                                                                  
  // The third stripe has the c2 mantissa and exponent
  // For our purposes, they can all be zero
  stripes[2] = 0L;
                  
  // The fourth stripe has the c1 mantissa and exponent
  // For our purposes, they can all be zero
  stripes[3] = 0L;
  
  // Sripe four also has the ISI thing for coag carts
  // Let's set it to be 1.05, somewhere in the middle of the
  // allowable range (.1 - 2.0)
  if (id >= MIN_COAG_CART_ID && id <= MAX_COAG_CART_ID)
    stripes[3] = 105L << 4;
                  
  // The fifth stripe has the lot ID in bits 29(msb) - 3(lsb) (0-based)
  stripes[4] = lot << 3;
                  
  // The sixth stripe has the expiration date:
  //    day = 29-25 (range 1-31), month = 24-21 (range 0-11)
  //    , year = 20-13 (range0-255 + 1970)
  // It also has the cartridge ID in bits 12-3
  stripes[5] = (day << 25) + ((month-1) << 21) + ((year-1970) << 13);
  stripes[5] += id << 3;
                  
  // The seventh stripe has the c0 mantissa and exponent
  // For our purposes, they can all be zero
  stripes[6] = 0L;
                  
  // Stripe 8 is blank
  stripes[7] = 0L;
                  
  // The ninth stripe has the15-bit checksum in bits 30-16
  stripes[8] = 0L;
                  
  // Before that, we turn on all the timing bits, to include them in
  // the checksum
  for (i = 0; i < 9; i++)
    stripes[i] += (1L << 31) + 1L + ((i%2) ? 0L : 2L);
                    
  // Calculate checksum
  byte_ptr = (unsigned char*)&stripes[0];
  checksum = 0;
  for (i = 0; i < 9 * 4 - 2; i++)
    {
    checksum += *byte_ptr++;
    }
                    
  // Penultimately, write the checksum
  stripes[8] += ((long)(0x7FFF & checksum)) << 16;
                  
                  
  // finally, copy barcode structure to buffer
  memcpy(return_data->data_ptr+1, &stripes[0], 36);
  return_data->data_ptr[37] = 32;

  }



//============================================================================
// scan_keymap_file
//
// Description: Reads the keymap data file for the id, month, day, year, lot,
//        and any file variable to be stored into the barcode label data
//  
// Inputs: 
//    ch      : character read from keyboard
//
// Outputs: 
//    Return_Data : pointer to buffer to hold barcode label 
//
// Returns: None
//----------------------------------------------------------------------------
void scan_keymap_file(char ch,IPC_msg_t* Return_Data)
{
  FILE *fp;
  char command;
  char line_seq[]="CHAR,ID,MONTH,DAY,YEAR,LOT,FILE,File Slot #,COMMENTS";
  int status = 1;
  int j=0;
  int id=0;
  int month=0;
  int day=0;
  int year=0;
  int lot_num=0;
  char kmbuf[100];
  
  // open the key map file
  if ( (fp = fopen(KEY_MAP_FILE,"r")) == NULL) status = 0;
  
  // The first line of the CSV file should be CHAR,ID,MONTH,DAY,YEAR,LOT,FILE,COMMENTS\n
  // Scan this line - if it is not shown as above assume the keymap file is invalid
  if (status == 1) 
  {
    command=' ';
    j=0;
    while (command != '\n' && j < 50) {
      fscanf(fp,"%c",&command);
      if (command != line_seq[j] && command != '\n') 
      {
        // the file is possibly corrupted and/or invalid
        status = 0;
        j=50;
      }
      else j++;
    }
  }
  
  // now search for the character command
  if (status == 1)
  {
    while (fscanf(fp,"%c",&command) != EOF && status == 1) {
      if (command == ch) 
      {
        status = 0; // leave the loop
        
        // found command - get the line and parse it
        fgets( kmbuf, 100, fp );
        csv_parse(kmbuf,&id,&month,&day,&year,&lot_num, CSV_Files[platter_slot[db_get_num_inserted_carts()] - 1],
                  &CSV_Slot_No[platter_slot[db_get_num_inserted_carts()] - 1]);
                  
        //printf("id = %i, file=%s, slot_no=%i\n", id, CSV_Files[platter_slot[db_get_num_inserted_carts()] - 1],
        //       CSV_Slot_No[platter_slot[db_get_num_inserted_carts()] - 1]);
        //getch();

        // if month equals zero call with max values - else call with
        // values read from file
        if (month == 0) 
        {
          Create_Cartridge(id, MAX_MONTH, MAX_DAY, MAX_YEAR, lot_num, Return_Data);
        }
        else
        {
          Create_Cartridge(id, month, day, year, lot_num, Return_Data);
        }
      }
      else
      {
        // not a command - increment to the next line
        while (fscanf(fp,"%c",&command) != EOF & command != '\n') ;
      }
    }
  }
  
  // finished
  if (fp) fclose(fp);
  
  return;
}

//============================================================================
// csv_parse
//
// Description: Parses a line of a CSV file into the output parameters
//        Made specificly for the keymap file
//        The format of the string to be parsed must be (note commas)
//        ,<int>,<int>,<int>,<int>,<int>,<string>,<string>
//  
// Inputs: 
//    buf   : string to be parsed
//
// Outputs: 
//    id    : id for cartridge
//    month   : month for cartridge
//    day   : day for cartridge
//    year    : year for cartridge 
//    lot_num : lot number for cartrdidge
//    buf   : inserted at the front is the FILE field
//
// Returns: None
//----------------------------------------------------------------------------
void csv_parse(char *buf,int *id,int *month,int *day,int *year,int *lot_num, char *filename, int *use_slot_no)
{
  char tbuf[255];
  // Parse buf
  int j=1; // skip 0 element - should be a ','
  int k=0;
  int l=0;
  
  // load int's
  for (l=0; l < 7; l++) {
    k=0;
    while (buf[j] != ',') {
      tbuf[k]=buf[j];
      j++;
      k++;         
    }
    j++; // increment past the ','
    tbuf[k]='\0';
    switch(l) {
      case 0:
        *id = atoi(tbuf);    
        break;
      case 1:
        *month = atoi(tbuf);
        break;
      case 2:
        *day = atoi(tbuf);
        break;
      case 3:
        *year = atoi(tbuf);
        break;
      case 4:
        *lot_num = atoi(tbuf);
        break;
      case 5:
        strcpy(filename, tbuf);
        break;
      case 6:
        *use_slot_no = atoi(tbuf);
        break;
      default:
        break;
    }
  }
  
  return;
}

void Build_CSV_Curve_Signature(int slot_no, char *buf, int test_id, int led)
  {
  const char *stds_sigs[] = {"White1 / LED%d Standard Film curve", "White2 / LED%d Standard Film curve",
                             "Black / LED%d Standard Film curve"};
                             
  if (slot_no <= 6 && test_id == CART_IQC_TYPE)
    {
    sprintf(buf, "Slot %i Reflectance IQC/LED%i curve", slot_no, led );
    }  
  else if (slot_no <= 6)
    {
    sprintf(buf, "Slot %d %s curve", slot_no, test_id == CART_FILM_TYPE ? "Film" : 
      (test_id == CART_ECH_TYPE ? "Echem" : "Coag"));
    }
  else
    {
    sprintf(buf, stds_sigs[(slot_no - 7) / 7], ((slot_no - 7) % 7) + 1);
    }
  }

//============================================================================
// LoadCurveFromCSV
//
// Description: Loads a film surve from a csv file generated during a trace mode
//      run
//  
// Inputs: 
//    filename  - file to read from
//    slot_no   - 1 to 6 for slots, 7 to 27 for standards (= simulations slot number)
//    use_slot_no - for slot_no = [1, 6], specific film curve from csv to load
//    databuf - pointer to data buffer
//
// Outputs: None
//
// Returns: True if entire curve was loaded from the file; false otherwise
//----------------------------------------------------------------------------
BOOLEAN LoadCurveFromCSV(const char * filename, int slot_no, int use_slot_no, IPC_msg_t *databuf, 
                         BOOLEAN dry_data, int test_id, int led)
  {
  BOOLEAN             status = FALSE, found = FALSE;
  FILE               *f;
  char                buf1[1024], buf2[1024], *p;
  Reduced_Entry_Type *retp = (Reduced_Entry_Type*)(databuf->data_ptr + 8);
  Reduced_Echem_Entry_Type *echemp = (Reduced_Echem_Entry_Type*)(databuf->data_ptr + 8);
  Reduced_Coag_Entry_Type  *coagp = (Reduced_Coag_Entry_Type*)(databuf->data_ptr + 8);
  float               ws1_rem, ws2_rem, bs_rem;
  int                 i;
  Barcode_Label_t     barcode;
  TestParam_Cnfg_t    params;
  int                 at_led[6] = {1, 2, 6, 3, 4, 5}, led_index = 0;
  int                 cont = 0;

  f = fopen(filename, "r");
  if (f)
    {
    
    // we need the standards delta time, find it first
    *(float*) &databuf->data_ptr[4] = ipc_float_swap(0.0f);
    
    if (slot_no <= 6)
      {
      sprintf(buf1, "Slot = %d", use_slot_no);
      while (fgets(buf2, sizeof(buf2), f) != NULL)
        {
        if (strstr(buf2, buf1) != NULL) // found it
          {
          
        // if this is an IQC test, go to the right LED number
          if (test_id == CART_IQC_TYPE && at_led[led_index] != led)
            {
            led_index++;
            continue;
            }
          
          if (test_id == CART_FILM_TYPE)
            {
            p = strstr(buf2, "Delta Time = ");
            if (p)
              {
              p += strlen("Delta Time = ");
              *(unsigned long*) &databuf->data_ptr[4] = ipc_long_swap(atol(p));
              }
            }
            
          // on the same line, we have the remission standards; set the emulators rem stds
          // to what was read by the unit during the trace (echem needs echem cal)
          // (coag needs isi and geometric mean (defaults to 1.5)
          {
          Cal_t cal;
          
          
          if (test_id == CART_ECH_TYPE)
            {
            p = strstr(buf2, "Echem slope,offset (m,b):");
            
            if (p)
              {
              p += strlen("Echem slope,offset (m,b):");
              
              p = strtok(p, ",");
              p = strtok(NULL, ",");
              ws1_rem = (float)atof(p);
              
              p = strtok(NULL, ",");
              ws2_rem = (float)atof(p);
              
              
              db_get_cal_rec(&cal);
              cal.ech_m = ws1_rem;
              cal.ech_b = ws2_rem;
              db_set_cal_rec(&cal);
              }
            }
          else if (test_id == CART_COAG_TYPE)
            {
            p = strstr(buf2, "ISI#=");
            db_get_cart_rec((BYTE)slot_no, &barcode);
            if (p)
              {
              p += strlen("ISI#=");              
              ws1_rem = (float)atof(p);
              barcode.lot_arguments.coag_coding_t.isi = ws1_rem;              
              db_add_to_platter((BYTE)slot_no, &barcode);
              }
              
            p = strstr(buf2, "Mean=");
            
            if (p)
              {
              p += strlen("Mean=");
              ws1_rem = (float)atof(p);
              db_assign_current_analyte(barcode.cart_id);
              if (db_get_UIPcnfg_params_rec(&params))
                {
                params.special_param.special_coag_t.geometric_mean = ws1_rem;
                db_set_UIPcnfg_params_rec(&params);
                }
              }
            }
            
          else if (test_id == CART_FILM_TYPE || test_id == CART_IQC_TYPE)
            {
            p = strstr(buf2, "Remission Standards (W1,W2,Blk):");
            
            if (p)
              {
              p += strlen("Remission Standards (W1,W2,Blk):");
              for (i = 0, p = strtok(p, ","); i < 4; i++, p = strtok(NULL, ","))
                {
                switch (i)
                  {
                case 0:
                  break; // this is the "Remission Standards..." line, so skip
                case 1:
                  ws1_rem = (float)atof(p);
                  break;
                case 2:
                  ws2_rem = (float)atof(p);
                  break;
                case 3:
                  bs_rem = (float)atof(p);
                  break;
                  }
                }
              db_get_cal_rec(&cal);
              cal.ws1_rem[led - 1] = ws1_rem;
              cal.ws2_rem[led - 1] = ws2_rem;
              cal.blk_rem[led - 1] = bs_rem;
              db_set_cal_rec(&cal);
              }            
            }
          
          }
    
          break;
          }
        }
      }
    
    // prepare the rest of the header
    if (test_id == CART_ECH_TYPE)
      databuf->data_ptr[0] = TESTRES_ECHEM;
    else if (test_id == CART_COAG_TYPE)
      databuf->data_ptr[0] = TESTRES_COAG;
    else
      databuf->data_ptr[0] = TESTRES_FILM;
    databuf->data_ptr[1] = slot_no;
    databuf->data_ptr[2] = dry_data * 2; // progression curve or dry data
    databuf->data_ptr[3] = led;

    
    // scan through the file until we find the line containing "Slot <slot_no> Film Curve"
    Build_CSV_Curve_Signature(slot_no <= 6 ? use_slot_no : slot_no, buf1, test_id, led);
    //printf("signature = %s\n\n", buf1);
    //getch();
    strupr(buf1);
    
    while (fgets(buf2, sizeof(buf2), f) != NULL)
      {
      strupr(buf2);
      if (strstr(buf2, buf1) != NULL) // found it
        {
        found = TRUE;
        break;
        }
      }
    
    if (found)
      {
      // skip the next line
      fgets(buf2, sizeof(buf2), f);
      
      // each line has the format: Timestamp, Running_Average, Photodiode, #_conversion, RSA
      //            echem  format: Timestamp, Relay_state, Running_average, max counts, #_conversions, RSA
      while (1) // will exit loop via break
        {
        if (!fgets(buf2, sizeof(buf2), f))
          break;

          
        if (!strchr(buf2, ',')) // end of data
          {
          if (test_id == CART_ECH_TYPE)
           databuf->byte_cnt = (WORD)((DWORD)echemp - (DWORD)databuf->data_ptr); 
          else if (test_id == CART_COAG_TYPE)
            databuf->byte_cnt = (WORD)((DWORD)coagp - (DWORD)databuf->data_ptr); 
          else
           databuf->byte_cnt = (WORD)((DWORD)retp - (DWORD)databuf->data_ptr);
          status = TRUE;
          break;
          }
        
        if (test_id == CART_ECH_TYPE)
          {
          // Timestamp
          p = strtok(buf2, ",");
          echemp->timestamp = ipc_long_swap(atol(p));
          
          // Relay state
          p = strtok(NULL, ",");
          echemp->echem_relay = ipc_word_swap(atoi(p) + DAT_OPTICAL_SLOT6);
          
          // Running average
          p = strtok(NULL, ",");
          echemp->running_average = ipc_float_swap((float)atof(p));
          
          // Max_counts
          p = strtok(NULL, ",");
          echemp->max_a2d_counts = ipc_word_swap(atoi(p));
          
          // Number of conversions
          p = strtok(NULL, ",");
          echemp->number_of_conversions = ipc_word_swap(atoi(p));
          
          // RSA
          p = strtok(NULL, ",");
          echemp->running_squared_average = ipc_float_swap((float)atof(p));
          
          echemp++;
          }
        else if (test_id == CART_COAG_TYPE)
          {
          // Timestamp
          p = strtok(buf2, ",");
          coagp->timestamp = ipc_long_swap(atol(p));
          
          // running average
          p = strtok(NULL, ",");
          coagp->running_average = ipc_float_swap((float)atof(p));
          
          coagp++;
          }
        else if (test_id == CART_FILM_TYPE || test_id == CART_IQC_TYPE)
          {
          
          // Timestamp
          p = strtok(buf2, ",");
          retp->timestamp = ipc_long_swap(atol(p));
          
          // skip this one if timestamp is 0
          switch (ipc_long_swap(retp->timestamp))
            {
            case 0:
            case 0xFFFFFFFF:
              cont = !dry_data;
              break;
            default:
              cont = dry_data;
            }
          if (cont)
            continue;
          
          
          // RA
          p = strtok(NULL, ",");
          retp->running_average = ipc_float_swap((float)atof(p));
          
          // Photodiode
          p = strtok(NULL, ",");
          retp->lagging_count = ipc_word_swap(atoi(p));
          
          // #_conversions
          p = strtok(NULL, ",");
          retp->number_of_conversions = ipc_word_swap(atoi(p));
          
          // RSA
          p = strtok(NULL, ",");
          retp->running_squared_average = ipc_float_swap((float)atof(p));
          
          
          retp++;
          }
        }
      }
      
    
    fclose(f);
    }
  else
    {
    printf("Could not open file %s\nPress any key to continue...", filename);
    getch();
    }
  return status;
  }

//============================================================================
// LoadTraceFromCSV
//
// Description: Loads a film trace from a csv file generated during a trace mode
//      run
//  
// Inputs: 
//    filename  - file to read from
//    slot_no   - 1 to 6 for slots, 7 to 27 for standards (= simulations slot number)
//    use_slot_no - for slot_no = [1, 6], specific film curve from csv to load
//    databuf - pointer to data buffer
//    test_id - Cart_Options_e value
//
// Outputs: None
//
// Returns: True if entire curve was loaded from the file; false otherwise
//----------------------------------------------------------------------------
BOOLEAN LoadTraceFromCSV(const char * filename, int slot_no, int use_slot_no, IPC_msg_t *databuf, int test_id)
  {
  BOOLEAN     status = FALSE, found = FALSE;
  FILE        *f;
  char        buf1[1024], buf2[1024], *p;
  WORD        *wp = (WORD*)&databuf->data_ptr[8];
  WORD        delimiter, counts;
  DWORD       timestamp;
  
  f = fopen(filename, "r");
  if (f)
    {
    // prepare the header
    if (test_id == CART_ECH_TYPE)
      databuf->data_ptr[0] = TESTRES_ECHEM;
    else if (test_id == CART_FILM_TYPE)
      databuf->data_ptr[0] = TESTRES_FILM;
    else
      databuf->data_ptr[0] = TESTRES_COAG;
      
    databuf->data_ptr[1] = slot_no;
    databuf->data_ptr[2] = 1; // trace data
    databuf->data_ptr[3] = (slot_no <= 6) ? Slot_To_LED[slot_no - 1] : 0;
    *(DWORD*)&databuf->data_ptr[4] = 0; // stds delta time n/a
    
    // scan through the file until we find the line containing "Slot <slot_no> Film Curve"
    strcpy(buf1, "Trace data for ");
    Build_CSV_Curve_Signature(slot_no <= 6 ? use_slot_no : slot_no, buf1 + strlen(buf1), test_id, 0);
    strupr(buf1);
    while (fgets(buf2, sizeof(buf2), f) != NULL)
      {
      strupr(buf2);
      if (strstr(buf2, buf1) != NULL) // found it
        {
        found = TRUE;
        break;
        }
      }
    
    if (found)
      {
      // skip the next line
      fgets(buf2, sizeof(buf2), f);
      
      // each line has the format: Delimiter, [relay state,] timestamp, a/d reading
      while (1) // will exit loop via break
        {
        
        // read the line
        if (!fgets(buf2, sizeof(buf2), f))
          break;
        
        // does this line still have data on it?
        if (!strchr(buf2, ',')) // end of data
          {          
          break;
          }
          
        // first read token will be -1 delimiter or value
        p = strtok(buf2, ",");
        if (!p)
          break;
        delimiter = atoi(p);
        
        *wp++ = ipc_word_swap(delimiter);
        
        if (delimiter == 0xFFFF)
          {
          
          if (test_id == CART_ECH_TYPE)
            {
            p = strtok(NULL, ",");
            if (!p) break;
            *wp++ = ipc_word_swap(atoi(p) + DAT_OPTICAL_SLOT6);
            }          
          else if (test_id == CART_FILM_TYPE)
            *wp++ = 0; // garbage
          
          p = strtok(NULL, ",");
          if (!p) break;
          timestamp = atol(p);
          
          p = strtok(NULL, ",");
          if (!p) break;
          counts = atoi(p);
          
          *(DWORD*)wp = ipc_long_swap(timestamp);
          wp += 2;
          
          *wp++ = ipc_word_swap(counts);          
          }
        }
        // set the size of the buffer
        databuf->byte_cnt = (WORD)((DWORD)wp - (DWORD)databuf->data_ptr);
        status = TRUE;
        
      }
      
    
    fclose(f);
    }
  return status;
  }

int ishex(char c)
  {
  if ((c >= '0' && c <= '9') ||
      (c >= 'a' && c <= 'f') ||
      (c >= 'A' && c <= 'F'))
    return 1;
  return 0;
  }

void serialize_message_file(const char *filename, IPC_msg_t* Return_Data)
  {
  FILE *f;
  int i, j, ctr = 0;
  char buf[3] = {0, 0, 0}, c;
  int hdr_bytes = 7;
  
  f = fopen(filename, "r");
  if (!f)
    {
    printf("%s at %i: Could not open file %s for reading. Press any key to continue.\n", 
           __FILE__, __LINE__, filename);
    getch();
    return;
    }
  
  i = 0; // i is number of bytes read from file so far
  j = 0; // j is index into hex char buffer of 2
  while (!feof(f))
    {
    // read two hex characters
    buf[j] = fgetc(f);
    
    if (!ishex(buf[j]))
      continue;
      
    j += 1;
    if (j == 2)
      {
      c = (char)strtol(buf, NULL, 0x10);
      if (i >= hdr_bytes)
        {
        Return_Data->data_ptr[i - hdr_bytes] = c;
        }
      else if (i == 4)
        Return_Data->ID = c;
        
      
      i += 1;
      j = 0;
      }
    }
  fclose(f);
  Return_Data->byte_cnt = i - 3 - hdr_bytes;
  
  }

#endif  // __UIP_RTP_INTEGRATION__

