/******************************************************************************
 *
 * RTips Technologies, Bangalore (www.rtipsonline.com)
 * 
 * This sample demonstrates the use of General Purpose Flags to conditionally 
 * execute a message. It creates a BC to RT message and makes its execution 
 * conditional to the value of GPF3 being 1. This is done by setting the 
 * condition code field of aceBCOpCodeCreate to ACE_CNDTST_GP3_1. 
 * Based on user input, this messages is enabled for transmission by setting 
 * the value of GPF3 to 1 by calling aceBCSetGPFState.
 *
 * Many portions of this file are adapted from the bcdemo.c sample provided in
 * the AceXtreme SDK (BU-69092Sx) of M/s. Data Device Corporation
 *
 * Author: Ganesh Okade
 * Last updated: Nov 19, 2024
 ******************************************************************************/

/* Include Files */
#ifdef WIN32
#include <windows.h>
#include "stdemace.h"
#include <conio.h>
#endif

#ifdef LINUX
#include <emacepl/stdemace.h>
#include "../linuxutil.h"
#endif

#ifdef VX_WORKS
#include "../LibPrj/include/stdemace.h"
#include "../utils/vxwrksuti.h"
#endif

#ifdef INTEGRITY
#include "../Integrity_Samples.h"
#endif

/* define data blocks */
#define DBLK1   1

/* define message constants */
#define MSG1    1

/* define opcodes */
#define OP1     	1
#define OP_CAL_MSG1 2
#define OP_GPF1_CLR 3

/* define frame constants */
#define MNR1    1
#define MJR     2

/*******************************************************************************
 * Name:    PressAKey
 *
 * Description:
 *
 *      Allows application to pause to allow screen contents to be read.
 *
 * In   none
 * Out  none
 ******************************************************************************/
static void PressAKey()
{
    /* flush input buffer */
    while (kbhit())
    {
        getchar();
    }

    printf("\nPress <ENTER> to continue...");

    /* flush the output buffer */
    fflush(stdout);

    while (!kbhit())
    {
        /* wait for keypress... */
        Sleep(10);
    }

    /* flush input buffer */
    while (kbhit())
    {
        getchar();
    }
}

/*******************************************************************************
 * Name:    PrintOutError
 *
 * Description:
 *
 *      This function prints out errors returned from library functions.
 *
 * In   result - the error number
 * Out  none
 ******************************************************************************/
static void PrintOutError(S16BIT nResult)
{
   char buf[80];
   aceErrorStr(nResult,buf,80);
   printf("RTL Function Failure-> %s.\n",buf);
}

/*******************************************************************************
 * Name:    DisplayDecodedMsg
 *
 * Description:
 *
 *      This function displays the information of a MSGSTRUCT to the screen.
 *
 * In   nMsgNum     Number of the message
 * In   pMsg        Relavant information of the message
 * Out  none
 ******************************************************************************/
static void DisplayDecodedMsg(S16BIT nMsgNum,MSGSTRUCT *pMsg)
{
    U16BIT i;
    char szBuffer[100];
    U16BIT wRT,wTR1,wTR2,wSA,wWC;

    /* Display message header info */
    printf("MSG #%04d.  TIME = %08dus    BUS %c   TYPE%d: %s ",nMsgNum,
        pMsg->wTimeTag*2,pMsg->wBlkSts&ACE_MT_BSW_CHNL?'B':'A',
        pMsg->wType, aceGetMsgTypeString(pMsg->wType));

    /* Display command word info */
    aceCmdWordParse(pMsg->wCmdWrd1,&wRT,&wTR1,&wSA,&wWC);
    sprintf(szBuffer,"%02d-%c-%02d-%02d",wRT,wTR1?'T':'R',wSA,wWC);
    printf("\n            CMD1 %04X --> %s",pMsg->wCmdWrd1,szBuffer);

    if(pMsg->wCmdWrd2Flg)
    {
        aceCmdWordParse(pMsg->wCmdWrd2,&wRT,&wTR2,&wSA,&wWC);
        sprintf(szBuffer,"%02d-%c-%02d-%02d",wRT,wTR2?'T':'R',wSA,wWC);
        printf("\n        CMD2 %04X --> %s",pMsg->wCmdWrd2,szBuffer);
    }

    /* Display transmit status words */
    if((wTR1==1) || (pMsg->wBlkSts&ACE_MT_BSW_RTRT))
    {
        if(pMsg->wStsWrd1Flg)
            printf("\n            STA1 %04X",pMsg->wStsWrd1);
    }

    /* Display Data words */
    for(i=0; i<pMsg->wWordCount; i++)
    {
        if(i==0)
            printf("\n            DATA ");

      printf("%04X  ",pMsg->aDataWrds[i]);

      if((i%8)==7)
        printf("\n                 ");
   }

    /* Display receive status words */
    if((wTR1==0)  && !(pMsg->wBlkSts&ACE_MT_BSW_RTRT))
    {
        if(pMsg->wStsWrd1Flg)
            printf("\n            STA1 %04X",pMsg->wStsWrd1);
    }

    if(pMsg->wStsWrd2Flg)
        printf("\n            STA2 %04X",pMsg->wStsWrd2);

    /* Display Error information */
    if(pMsg->wBlkSts & ACE_MT_BSW_ERRFLG)
        printf("\n ERROR: %s",aceGetBSWErrString(ACE_MODE_MT,pMsg->wBlkSts));

    printf("\n\n");
}

/*******************************************************************************
 * Name:    GetBCHBufDecodedMsgs
 *
 * Description:
 *
 *      This function creates an BC stack file in ASCII text using all msgs
 *      read from the ACE and outputs to a file.
 *
 * In   DevNum - the device number of the hardware to be accessed.
 * Out  none
 ******************************************************************************/
static void GetBCHBufDecodedMsgs(S16BIT DevNum)
{
#ifdef INTEGRITY
    Task kbhit_task;
#else
    FILE *pFile = NULL;
#endif
    S16BIT nResult      = 0x0000;
    U32BIT dwHBufLost   = 0x00000000;
    U32BIT dwMsgCount   = 0x00000000;
    U32BIT dwCurCount   = 0x00000000;
    U16BIT wRepeatCount = -1;
    MSGSTRUCT sMsg;
	S16BIT wResult          = 0x0000;
	U16BIT wStatus = 0;
	int quitLoop = 0;
	char key;
	
    U16BIT wBuffer[64] =
    {
        0x1111, 0x2222, 0x3333, 0x4444, 0x1111, 0x2222, 0x3333, 0x4444,
        0x1111, 0x2222, 0x3333, 0x4444, 0x1111, 0x2222, 0x3333, 0x4444,
        0x1111, 0x2222, 0x3333, 0x4444, 0x1111, 0x2222, 0x3333, 0x4444,
        0x1111, 0x2222, 0x3333, 0x4444, 0x1111, 0x2222, 0x3333, 0x4444
    };

#ifndef INTEGRITY
    /* Open file */
    pFile = fopen("bcstack.txt","w");
#endif

    printf("\n** The BC will now send %d messages",wRepeatCount);

    /* Start BC */
    aceBCStart(DevNum,MJR,wRepeatCount);

    /* Run Information */
    printf("\n** BC Device Number %d, outputting to 'bcstack.txt', press <ENTER> to stop **\n\n", DevNum);

    printf("** Messages will also be output to the screen\n");

	/* Set GPF 3 to 1, this will get set to 0 once BC is started and trigger is seen by BC */
	wResult += aceBCSetGPFState(DevNum, ACE_GPF3, ACE_GPF_SET);

    PressAKey();
    printf("\n\n");

#ifdef INTEGRITY
    CreateProtectedTask(1,(Address)kbhit_task_func,0x1000,"kbhit", &kbhit_task);
    RunTask(kbhit_task);
#endif
		
	printf("\n\nPress 'q' to quit or enter to resend message \n\n");
    while(quitLoop == 0)		
    {
		if(kbhit())
		{
			key = _getch();
			if(key == 'q')
			{
				quitLoop = 1;
			}
			else
			{
				wResult += aceBCSetGPFState(DevNum, ACE_GPF3, ACE_GPF_SET);
			}
		}		

  		if(aceBCGetMsgFromIDDecoded(DevNum,MSG1,&sMsg,TRUE)==1)
		{
			/* Display MSG1 to screen */
			dwCurCount++;
			DisplayDecodedMsg(dwCurCount,&sMsg);
	
			Sleep(1);
		}
	}
	
	/* Throw out key */
	getch();

#ifndef INTEGRITY
    /* Close out of file */
    fclose(pFile);
#endif

    /* Stop BC */
    aceBCStop(DevNum);

    printf("\n");
}

/*******************************************************************************
 * Name: main
 *
 * Description:
 *
 *      Program entry point.
 *
 * In   none
 * Out  none
 ******************************************************************************/
#ifndef VX_WORKS
int main(void)
#else
int bcdemo(void)
#endif
{
    /* Variables */
    S16BIT DevNum           = 0x0000;
    S16BIT wResult          = 0x0000;
    S16BIT wSelection       = 0x0000;
    S16BIT aOpCodes[10]     = { 0x0000 };
    U32BIT u32BusSelection  = 1;

	U16BIT wBuffer[64] =
    {
        0x1111, 0x2222, 0x3333, 0x4444, 0x1111, 0x2222, 0x3333, 0x4444,
        0x1111, 0x2222, 0x3333, 0x4444, 0x1111, 0x2222, 0x3333, 0x4444,
        0x1111, 0x2222, 0x3333, 0x4444, 0x1111, 0x2222, 0x3333, 0x4444,
        0x1111, 0x2222, 0x3333, 0x4444, 0x1111, 0x2222, 0x3333, 0x4444
    };

    /* Get Logical Device # */
    printf("\nSelect BC Logical Device Number (0-31):\n");
    printf("> ");

    scanf("%hd", &DevNum);
	
    /* Initialize Device */
    wResult = aceInitialize(DevNum,ACE_ACCESS_CARD,ACE_MODE_BC,0,0,0);

    if(wResult)
    {
        printf("Initialize ");
        PrintOutError(wResult);
        PressAKey();
        return 0;
    }	

	wResult = aceBCDataBlkCreate(DevNum,DBLK1,32,wBuffer,32);

	/* Create message block */
    aceBCMsgCreateBCtoRT(
        DevNum,              /* Device number                    */
        MSG1,                /* Message ID to create             */
        DBLK1,               /* Message will use this data block */
        1,                   /* RT address                       */
        1,                   /* RT subaddress                    */
        10,                  /* Word count                       */
        0,                   /* Default message timer            */
        ACE_BCCTRL_CHL_A);   /* use chl A options                */

	/* Create XEQ opcode that will use msg block and only send the message when GP3 = 1 */
    aceBCOpCodeCreate(DevNum,OP1,ACE_OPCODE_XEQ,ACE_CNDTST_GP3_1,MSG1,0,0);

    
	/* Create CAL opcode that will call mnr frame from major */
    aceBCOpCodeCreate(DevNum,OP_CAL_MSG1,ACE_OPCODE_CAL,ACE_CNDTST_ALWAYS,MNR1,0,0);
	

	/* Create FLG opcode that clears (i.e. sets to 0) the value of General 
	   Purpose flag 3 */
    aceBCOpCodeCreate(DevNum,OP_GPF1_CLR,ACE_OPCODE_FLG,ACE_CNDTST_ALWAYS,0x0800,0,0);
		
    /* Create Minor Frame */
    aOpCodes[0] = OP1;		/* Execute MSG1					*/
	aOpCodes[1] = OP_GPF1_CLR;		/* Clear GPF3					*/	
	aceBCFrameCreate(DevNum,MNR1,ACE_FRAME_MINOR,aOpCodes,2,0,0);

    /* Create Major Frame */
    aOpCodes[0] = OP_CAL_MSG1;		/* Call Minor Frame             */	
	aceBCFrameCreate(DevNum,MJR,ACE_FRAME_MAJOR,aOpCodes,1,1000,0);

	
	GetBCHBufDecodedMsgs(DevNum);  
    
    /* Free all resources */
    wResult = aceFree(DevNum);

    if(wResult)
    {
        printf("Free ");
        PrintOutError(wResult);
        return 0;
    }

    /* Pause before program exit */
    PressAKey();

    return 0;
}

