  

/*  fi_exist.c
    For use with TM.EXE Version 4
    Stephen D. Anderson --- July 30, 1994

    Function fi_exist checks for the existence of a field instrument.

It sends universal command 0 and checks whether any response.  It tries
all possible polling addresses 3 times or until it gets a valid response.  
Windows are opened to show what is occurring.
    If there is a valid response, it gets long frame address, numb 
preambles, and other info of responding device; and returns 1.
    If there is a communication error, an error window and message are
displayed and 0 is returned.  
    If there is a command error, an error window and message are 
displayed and 0 is returned.
    If the field instrum is short-frame only, an error window and
message are displayed and 0 is returned.
    If the field device indicates that it requires EEPROM burn, an
error window and message are displayed and 0 is returned.
    If no field instrument is found, an error window and message are
displayed and 0 is returned.

    ON ENTRY:
    No arguments.  Uses global variables "addr[]" and "polling_addr".

    ON EXIT:
    returns 1 if success, 0 if not.

    REVISION LOG:


*/

#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "conio.h"
#include "bios.h"
#include "c:\cport\include\cport.h"
#include "tcxlwin.h"
#include "tcxlvid.h"
#include "tcxldef.h"
#include "tcxlinp.h"

byte fi_exist()

{
    extern byte send[], receive[], receive_err[];
    extern byte status1, status2;
    extern byte polling_addr, addr[];

    extern int send_rec(byte);
    extern byte Checksum(byte *, byte);
    extern byte Checkpar(byte *, byte);

    byte i,j,k;
    byte n_tries;
    byte cs_start;
    byte *r,*s,*re;
    byte start_delim[3] = {0xff, 0xff, 6};
    byte trial_address;
    byte byte_count;
    byte error,comm_error,command_error,old_device,needs_burn;
    int rec_bytes;
    byte *a;

    Wopen(3,18,16,62,2,WHITE|_BLUE,WHITE|_BLUE);
    WputCen("\n\nSearching For Field Instrument ... ");

    /*  build the xmit message. */
    for (i=0; i<=19; ++i) send[i]=0xff;    /* preamble. */
    send[i++]=2;    /*  start delimiter. */
    s=&send[i];         /* point to start of message. */
    send[i++] = 0;      /* space for address byte. */
    send[i++] = 0;      /* command. */
    send[i++] = 0;      /* byte count. */

    /*  try all addresses or until device found. */
    Wopen(10,25,13,55,1,WHITE|_GREEN,WHITE|_GREEN);

    /*  retry each address 3 times.  */
    for (n_tries=1; n_tries<=3; ++n_tries)
    {

        for (trial_address=0; trial_address<16; ++trial_address)
        {
            Wclear();
            Wputf("\n  Trying Polling Address %d ",trial_address);
            *s = 0x80 | trial_address;  /*  generate the short address. */
            send[i] = Checksum((send+20), i-20);    /* checksum byte. */

            /*  clear error flags. */
            error = 0; comm_error = 0; command_error = 0;
            old_device = 0; needs_burn = 0;

            rec_bytes = send_rec(i+1);  /*  do comm. */

            if ((rec_bytes & 0xff) != 0 ) 
            {
                ++error; continue;  /*  do next try. */
            }

            k = rec_bytes/256;

            /* find start delimiter.  */
            r = receive;
            for (j=1; j <= k; ++j)
            {
                if ((strncmp(r++, start_delim, 3)) == 0) break;
            }

            /* go to start delim and check numb bytes left. */
            j += 2; ++r;
            if (j > k)
            {
                ++error; continue;  /*  do next try. */
            }

            cs_start = j;   /* mark position. */

            ++j; ++r;       /* advance to address. */

            /* are there at least 2 characters left? */
            if ((k-j+1) < 2)
            {
                ++error; continue;  /*  do next try. */
            }

            /* do address and command match? */
            if ((strncmp(r, s, 2)) != 0)
            {
                ++error; continue;  /*  do next try. */
            }

            j += 2; r += 2;  /* skip to byte count. */
            if (j > k)
            {
                ++error; continue;  /*  do next try. */
            }

            byte_count = *r;    /*  save byte count. */

            ++j;  ++r;  /*  skip to status. */
            status1 = *r++; ++j;     /*  save it.  */
            status2 = *r++; ++j;

            /*  field instrum. reporting communication error? */
            if ((status1 & 0x80) != 0)
            {
                ++comm_error; continue; /*  do next try. */
            }

            /*  field instrum reporting command error? */
            if ((status1 == 6) || (status1 == 16))
            {
                ++command_error; continue;  /*  do next try. */
            }

            /* byte count either 12 or 14? */
            if ( (byte_count != 14) && (byte_count != 12))
            {
                ++error; continue;  /*  do next try. */
            }

            /*  now pointing at 1st byte of receive data. */
            a = addr;   /*  set pointer. */
            if (*r != 254)
            {
                /*  indicates possible older device. 
                do checksum to see if message otherwise OK. */
                j += 10;    /*  advance to checksum. */
                r = &receive[cs_start-1];   /* point to start delim. */
                re = &receive_err[cs_start-1];
                if (((Checksum(r, j-cs_start+1)) == 0) &&
                    ((Checkpar(re, j-cs_start+1)) == 0))
                    ++old_device;
                else
                    ++error;
                if (error == 0)
                    break;  /*  yes, old device.  
                                so break out of comm tries. */
                else
                    continue;   /*  else do next try. */
            }
            else
            {
                /*  indicates rev 5 (acceptable) device. 
                so finish the message. */

                r += 3;         /*  point to numb preambles. */
                *a++ = *r++;    /*  get numb preambles. */
                r -= 3;         /*  point to MFR ID. */
                *a++ = *r++;    /*  get MFR ID (1st byte of addr). */
                *a++ = *r++;    /*  get MFR DEVICE TYPE (2nd byte). */

                r += 6;     /*  point to DEVICE ID MSB (3rd addr byte).  */
                *a++ = *r++;    /*  get 3 bytes */
                *a++ = *r++;
                *a++ = *r++;

                r -= 6;         /*  back up to software rev of dev. */
                *a++ = *r++;    /*  get software rev of device. */
                *a++ = *r++;    /*  get hardware rev of device. */
                *a = *r;        /*  get flags of device.  */

                /*  check flags. */
                if ((*a & 2) != 0) ++needs_burn;

                /*  get checksum. */
                j += 12;    /*  advance to checksum. */
                r = &receive[cs_start-1]; /*  point to start delim. */
                re = &receive_err[cs_start-1];
                if (((Checksum(r, j-cs_start+1)) != 0) ||
                    ((Checkpar(re, j-cs_start+1)) != 0))
                    ++error;

                if (error)
                    continue;   /*  do next try. */
                else
                    break;      /*  quit comm tries.  */
            }
        }
        if ((error == 0) && (comm_error == 0) && (command_error == 0))
            break;  /*  leave try address loop. */
    }

    if (comm_error != 0)
    {
        WpopUp(CNT_CNT,10,10,20,50,3,WHITE|_RED,WHITE|_RED);
        WputCen("\n\nField Instrument Reported");
        WputCen("\nCommunication Error -- Can't");
        WputCen(" Continue.");
        WputCen("\n\n  Hit any key to resume ");
        Beep(); KeyWait(); Wclose(); Wclose(); Wclose(); return(0);
    }

    if (command_error != 0)
    {
        WpopUp(CNT_CNT,10,10,20,50,3,WHITE|_RED,WHITE|_RED);
        WputCen("\n\n   Field Instrument Reported");
        WputCen("\n    Command Response Error -- Can't");
        WputCen(" Continue.");
        WputCen("\n\n   Hit any key to resume");
        Beep(); KeyWait(); Wclose(); Wclose(); Wclose(); return(0);
    }

    if (old_device != 0)
    {
        WpopUp(CNT_CNT,10,10,20,50,3,WHITE|_RED,WHITE|_RED);
        WputCen("\n\n  Cannot communicate with");
        WputCen("\n  this Field Instrument --  Must");
        WputCen("\n  have HART Rev. Level 5 ");
        WputCen("\n  Field Instrument");
        WputCen("\n\n  Hit any key to resume ");
        Beep(); KeyWait(); Wclose(); Wclose(); Wclose(); return(0);
    }

    if (needs_burn != 0)
    {
        WpopUp(CNT_CNT,10,10,20,50,3,WHITE|_RED,WHITE|_RED);
        WputCen("\n\n   Field Instrument Reported");
        WputCen("\n   That it Requires EEPROM Burn");
        WputCen("\n   Command -- Can't Continue.");
        WputCen("\n\n   Hit any key to resume");
        Beep(); KeyWait(); Wclose(); Wclose(); Wclose(); return(0);
    }

    if (error != 0)
    {
        WpopUp(CNT_CNT,10,10,20,50,3,WHITE|_RED,WHITE|_RED);
        WputCen("\n\n  No Field Instrument Found  ");
        WputCen("\n\n  Hit any key to resume  ");
        Beep(); KeyWait(); Wclose(); Wclose(); Wclose(); return(0);
    }

    /*  success. */
    delay(1000); Wclose(); Wclose();
    polling_addr = trial_address; return(1);
}

