/**************************************************************
$Workfile:   apientries.c  $
***************************************************************
**
** FIRMWARE, Copyright (C) 2000-2002 
** Ikanos Communications, Fremont, CA
** All rights reserved.
**
** The information and contents of this file are the
** proprietary information of Ikanos Communication and may not
** be disclosed or used without the formal written approval of
** Ikanos Communication
**
$Revision: 1.3 $
$Date: 2007/01/22 14:49:09 $ 
***************************************************************/

/***************************************************************
** This C header file containes the function prototype for IPOS API
**
***************************************************************/
#include <stdio.h>
#include "bmeconfig.h" 
#include "ipos.h"
#include "dapi.h"
#include "apilocal.h"
#include "time.h"

#include "eventlog.h"
#define TRUE 1
extern HWAPI_RET_VAL TransferBmeMessage(tBmeStruct *pBme);
extern HWAPI_RET_VAL ReceiveBmeMessage(tBmeStruct *pBme);
extern void bmeIntDisable(tBmeStruct *bmeStruct, BYTE intrMask);


int pollFreq [50];
int poll_index=0;
time_t prev_poll_time;
#ifdef BUP_DIAGS
int gotAnRx = 0;

#endif
int iposMsgParse(ipos_api_bme   * pApiBme, U8 *pMsg);
int  iposAutoCmd(ipos_api_bme *pApiBme, U8 *pMsg);
int  iposStatusCmd(ipos_api_bme *pApiBme, U8 *pMsg);
int  iposTstCmd(ipos_api_bme *pApiBme, U8 *pMsg);
int  iposCtrlCmd(ipos_api_bme *pApiBme, U8 *pMsg);
int  handleIposOptionalCmd(ipos_api_bme *pApiBme, U8 *pMsg);

/*************************************************************
     
     entry point for API expired processing 
        
        input: tick=period of polling in 100msec    
        return: IPOS_SUCCESS or IPOS_ERROR_CODE 
        
        Note: Used only if expiration of a asynch call is required  
        
*************************************************************/

int iposEntryAPiExp(int tick)
{

    int   i, intLevel;
    ipos_msg_buf  *pMsg;

    iposCbCtl pCb; 
    ipos_port_id pid; 
    U8 UID; 
    U32 uPar;

    for (i=0;i<IPOS_MAX_MSG;i++)
    {

        intLevel=iposIntLock();                             /* any procedure access msgbuf must be atomic   */

        pMsg=iposMsgFindMsg(i);

        if (pMsg==NULL)
        {
            iposIntUnlock(intLevel);
            printf("Can't find valid iposMsgBuf. Fatal\n"); /* should always have msg buf available */
            return(IPOS_ERROR_NO_MSGBUF);
        }

        if (pMsg->cbSet==IPOS_MSG_CALLBACK_SET)                  /* check msg_buf with callback pending     */
        {
            pMsg->tick--;                                   /* update the counter in each msgbuf for callback   */

            if (pMsg->tick<=0)                               /* expired?     callback with error msg    */
            {
                pMsg->tick=0; 
                pCb=(iposCbCtl) iposGetCallback(pMsg, &pid, &UID, &uPar);

                if (pCb!=NULL)
                {
                    iposIntUnlock(intLevel);                /* enter callback function: interrupt unlock */
                    pCb(pid,UID,uPar,IPOS_ERROR_EXPIRED,NULL);

                }

            }    /* if pMsg->tick */

        }        /*if cbser */

    }         /* for loop   */

    iposIntUnlock(intLevel);
    return(IPOS_SUCCESS);
}

void InitpollMonitorParms()
{
int i=0;

    for (i=0;i<50;i++)
    pollFreq[i]=0;

    prev_poll_time=0;


}

/*
 *
 *  CompleteBmeMessage
 *
 *  pollDmaDone has returned TRUE
 *
 *  Now receive the message from the BME and, if successful, parse the message.
 *
 *  Special note:  When ReceiveBmeMessage completes, the HIC transaction is complete
 *  and the semaphore guarding the BME/HIC may be released.  In fact it NEEDS to be
 *  released because the callback (called from iposMsgParse) may want to take the
 *  same semaphore.  But if ReceiveBmeMessage fails, the semaphore is NOT given.
 *  The variable semState (local to iposEntryRcvPoll) tracks whether the semaphore
 *  has been given.  Because CompleteBmeMessage may or may not give that semaphore,
 *  CompleteBmeMessage needs access to semState.  This the 2nd arg, an int *.
 *
 */

static int
CompleteBmeMessage( ipos_api_bme *pApiBme, U8 *pSemState )
{
    U8  *msgBf;
        int  errCode = IPOS_SUCCESS;

    // Read BME message from DMA FIFO

    if (ReceiveBmeMessage(pApiBme->pBme) == HWAPI_FAILED)
    {
        printf("FATAL ERROR: Failed to receive BME message \n");
        errCode = IPOS_ERROR_RECEIVE_FAILED;
    } else
    {
            /* parse received pmsgbuf   */

        msgBf=pApiBme->pBme->RxBmeMsg;
#ifdef USE_BME_INTERRUPT
        bmeIntEnable(pApiBme->pBme, MSG_RDY_IN_BME_DPRAM_INTR);
#endif
        iposSemGive(pApiBme->semBme);           /* release the bme Lock */
        *pSemState=1;                     /* bme Lock released: semState=1 */
        if ((errCode = iposMsgParse(pApiBme,msgBf))!= IPOS_SUCCESS)
          printf("FATAL ERROR: Failed to parse BME message \n");
    }

    return( errCode );
}

/************************************************************************
 
 iposEntryRcvPoll: for BME receiving path functions 
        
        input:  tick the polling period in msec     
        return value: IPOS_SUCCESS or error cdoe    

        note:   normal callback functions will  be called from here 
                Can be triggered by an ISR
        
************************************************************************/


int iposEntryRcvPoll(int tick, int bmeNum)          /* tick is the polling period in msec   */
{
    int i, waitTime;
    ipos_api_bme    *pApiBme;
    int start,end;
      time_t present_poll_time;
    int errorCode[ IPOS_MAX_BME ];
    U8 semState[ IPOS_MAX_BME ];
    U8 deferredMsg[ IPOS_MAX_BME ];
    U8 timeoutCount[ IPOS_MAX_BME ];
    U16 bmeIndex;
    U8 finished = 0;    /* yes or no */

    if (bmeNum<0||bmeNum>IPOS_MAX_BME)
    {
        return IPOS_ERROR;
    }

/* semState[ BME ] is 1 if the semaphore is NOT taken
   semState[ BME ] is 0 if the semaphore IS taken */

    if (bmeNum==0)
    {
        start=1;
        end=IPOS_MAX_BME;
        waitTime = IPOS_NO_WAIT;
    }
    else
    {
        start=bmeNum;
        end=bmeNum;
        waitTime = IPOS_CALL_EXPIRED_TICK;

    }

    for (i=start;i<=end;i++)
    {
    bmeIndex = i - 1;
    semState[ bmeIndex ] = 1;
    errorCode[ bmeIndex ] = IPOS_SUCCESS;
    timeoutCount[ bmeIndex ] = 0;
    }

    time (&present_poll_time);
    if (prev_poll_time==present_poll_time)
    {
        pollFreq[poll_index]++;
    }
    else
    {   
        poll_index++;
        if(poll_index>=50) poll_index=0;
        pollFreq[poll_index]=1;
    }

    prev_poll_time=present_poll_time;


    for (i=start;i<=end;i++)
    {
        /* check all bme which is running   */
        pApiBme=(ipos_api_bme *) iposGetBmeHandle(i);
    bmeIndex = i-1;
    deferredMsg[ bmeIndex ] = 0;

        if ((iposGetState(pApiBme)==IPOS_BME_RUN) &&
            (iposSemTake(pApiBme->semBme, waitTime) == OS_SUCCESS))
        {

            semState[ bmeIndex ] = 0;

            if (pollRxMsgReady(pApiBme->pBme) == TRUE)
            {

                bmeIntDisable(pApiBme->pBme, MSG_RDY_IN_BME_DPRAM_INTR);

                // Transfer BME message from BME memory to DMA FIFO
                if (TransferBmeMessage(pApiBme->pBme)==HWAPI_FAILED)
                {
#ifdef  NOTI                    
                    printf("FATAL ERROR: Failed to transfer BME message \n");
#endif
                    errorCode[ bmeIndex ] = IPOS_ERROR_RECEIVE_FAILED;
                } else
                {
                    deferredMsg[ bmeIndex ] = 1;
                }
#ifdef USE_BME_INTERRUPT
                if (deferredMsg[ bmeIndex ]==0)
                  bmeIntEnable(pApiBme->pBme, MSG_RDY_IN_BME_DPRAM_INTR);
#endif
            }

            if (deferredMsg[ bmeIndex ] == 0)
        {
        iposSemGive(pApiBme->semBme);           /* release the bme Lock if not already released */
        semState[ bmeIndex ] = 1;       /* more for appearances, but this cannot hurt */
        }

        /* if deferredMsg[ bmeIndex ] != 1, then semState[ bmeIndex ] == 0
           notice if deferredMsg is set, then semState[ bmeIndex ] was
           previously set to 0 and not modified */
        }
    }


/*
 *  deferredMsg is set to 1 if the corresponding BME (index: bmeIndex)
 *  has a message the host could not read initially
 *
 */

    do
    {
    finished = 1;
    for (i=start;i<=end;i++)
    {
        bmeIndex = i-1;

        if (deferredMsg[ bmeIndex ] != 0)
        {
        if (semState[ bmeIndex ] != 0)
          printf( "\niposEntryRcvPoll, internals inconsistent, index is %d\n", bmeIndex );
        
        pApiBme=(ipos_api_bme *) iposGetBmeHandle(i);
        if (pollDmaDone(pApiBme->pBme) != TRUE)
        {
                    timeoutCount[ bmeIndex ]++;
                    if (timeoutCount[ bmeIndex ] >= IPOS_TX_TIMEOUT)
                    {
                        printf("Rx Time Out bmeIndex %i  \n",bmeIndex);
                        errorCode[ bmeIndex ] = IPOS_ERROR_TX_TIMEOUT;

            pApiBme->pBme->fifoStatus=FIFO_EMPTY; 
            deferredMsg[ bmeIndex ] = 0;
#ifdef USE_BME_INTERRUPT
                        bmeIntEnable(pApiBme->pBme, MSG_RDY_IN_BME_DPRAM_INTR);
#endif
            }
            else
              finished = 0;
        }
        else    /* pollDmaDone(pApiBme->pBme) returned TRUE */
        {
            errorCode[ bmeIndex ] = CompleteBmeMessage( pApiBme, &semState[ bmeIndex ] );
            deferredMsg[ bmeIndex ] = 0;
        }

        if (semState[ bmeIndex ]==0 && deferredMsg[ bmeIndex ] == 0)
        {
           iposSemGive(pApiBme->semBme);        /* release the bme Lock if not already released */
           semState[ bmeIndex ] = 1;        /* more for appearances, but this cannot hurt */
            }
        }
    }

/* if some DMA transfer not complete, pause for a clock tick  */

    if (finished == 0)
          iposTaskDelay(1);
    }
      while (finished == 0);

    return(IPOS_SUCCESS);
}       /* for each bme loop    */



int iposMsgParse(ipos_api_bme   * pApiBme, U8 *pMsg)
{

    U8 opCode, dest;
    int errCode=IPOS_SUCCESS;

#ifdef BUP_DIAGS
    static int num = 0;
    static int first = 1;
#endif          

    /* autonomous msg? status request msg? control msg? */
    opCode=pMsg[_BmeMsgOPCODE_];
        if (pApiBme->pBme->hostResync) {
            if ((opCode != HPI_HOST_HOT_RESET) &&
                (opCode != HPI_HOST_RETRIEVE_BME_CONFIG) &&
                (opCode != HPI_HOST_RETRIEVE_PORT_CONFIG)) {
                  return (errCode);
            } else {
                      if (opCode == HPI_HOST_HOT_RESET)
                        /* Set hostResync to 0 to indicate that the hostResync is complete for this BME */
                        pApiBme->pBme->hostResync = 0;
                    }
        }
    dest= pMsg[_BmeMsgDEST_];

    if (dest==0)             /* destination ==0:always autonomous message   */
    {
#ifdef  USE_BMEVERPATCH
        extern  void    uiLogDeviceVer(int bmeNum, int  len, char *string);

        if (opCode==DEVICE_VERSIONS)
        {
            uiLogDeviceVer(pApiBme->bmeNum, pApiBme->pBme->Port[0].PortParms.DeviceVerParms.VersionLen,
                           pApiBme->pBme->Port[0].PortParms.DeviceVerParms.VersionStr); 
            return IPOS_SUCCESS;
        }
#endif          

        errCode=iposAutoCmd(pApiBme,pMsg);
        return  errCode;

    }

    /* destination !=0 follows  */

    if ((opCode>=1 && opCode<= LAST_CTRL_COMMAND)|| (opCode==PERIODIC_REPORTS_ENABLE))
    {
        errCode=iposCtrlCmd(pApiBme,pMsg); 
    }


    else if (opCode> LAST_CTRL_COMMAND && opCode<= LAST_TEST_COMMAND)
    {
        errCode=iposTstCmd(pApiBme,pMsg);
    } else if (opCode>LAST_TEST_COMMAND && opCode<=LAST_AUTO_COMMAND)
      {
        errCode=iposAutoCmd(pApiBme, pMsg);
    } else if (opCode>LAST_AUTO_COMMAND && opCode<=LAST_STATUS_COMMAND)
    {
        errCode=iposStatusCmd(pApiBme, pMsg);
    } else if (opCode == HPI_OP_CMD)
    {
        errCode = handleIposOptionalCmd(pApiBme, pMsg);

    }

#ifdef BUP_DIAGS
   else if (opCode == 0xff)
   {
        if (first)
        {
            printf("Got HIC messages from BME:\n");
            first = 0;
        }
        printf("%d\r", num++);
        errCode = 0;
        gotAnRx = TRUE;
    } 
#endif
    return errCode;

}

int  iposCtrlCmd(ipos_api_bme *pApiBme, U8 *pMsg)
{

    U8  dest,  ack, UID;                    /* for control conmmand: dest and ack needed for callback   */
    U32 uPar;
    int status;

    ipos_msg_buf    *pBuf;
    iposCbCtl       pCb;  /* callback function for control command  */
    ipos_port_id    pid;
    time_t present_time;

    /* dest serves as the index to the msgBuf   */
    dest    =pMsg[_BmeMsgDEST_];
    ack     =pMsg[_BmeMsgACK_];

    /* check the msg is ready for callback  */
    if (dest<=0||dest>=IPOS_MAX_MSG)
    {
        printf("FATAL ERROR: Destination is %d in iposCtrlCmd\n", dest);
        return  IPOS_ERROR_MSG_SOURCE;

    }

    pBuf = iposMsgFindMsg(dest);

    if ((pBuf == NULL) || (pBuf->cbSet!=IPOS_MSG_CALLBACK_SET))
    {

/* inspection of iposMsgFindMsg shows error check above
   should prevent iposMsgFindMsg from returning NULL */

        if (pBuf == NULL)
          printf("FATAL ERROR: Logic error with iposMsgFindMsg in iposCtrlCmd, dest = %d\n", dest);
    else
          printf("FATAL ERROR: Callback not set for destination %d in iposCtrlCmd\n", dest );
        return  IPOS_ERROR_CALLBACK_NOT_SET;
    }

    pCb=(iposCbCtl) iposGetCallback(pBuf,&pid,&UID,&uPar);

    if (pMsg[_BmeMsgOPCODE_]==PORT_START)
    {
        time (&present_time);
#ifndef ALASKA
        printf ("\nipos idx: %i present %lis start %lis diff %lis",pBuf->index,(UINT32)present_time,
                (UINT32) pBuf->start_timestamp,(UINT32)(present_time-pBuf->start_timestamp));
#endif
    }

    iposMsgFree(pBuf);                  /* callback Msg Buf not needed: Free! */

    if (pCb!=NULL)
    {
      if (ack==ACK_SUCCESS)
      {
        status=IPOS_SUCCESS;
        if (pMsg[_BmeMsgOPCODE_] == PORT_START)
          pCb(pid,UID,uPar,status,
              &(pApiBme->pBme->Port[pid.portNum].PortParms.PortStatusExtParms));
        else {
                      if (pMsg[_BmeDataLENGTH_] > 0) {
                pCb(pid,UID,uPar,status,&pMsg[_BmeDataLENGTH_]);
                        } else {
                pCb(pid,UID,uPar,status,NULL);
                        }
                }
      }
      else
      {
        status= (int) ack;
        if (pMsg[_BmeDataLENGTH_] > 0)
          pCb(pid,UID,uPar,status,&pMsg[_BmeDataStart_]);
        else
          pCb(pid,UID,uPar,status,NULL);
      }

    }

    return IPOS_SUCCESS;

}


int  iposAutoCmd(ipos_api_bme *pApiBme, U8 *pMsg)
{

    U8  src,ack,opCode;             /* for autonomous msg: src and opcode needed for callback */
    ipos_port_id    pid;

    /* parse the auto command message  and callback  */
    opCode=pMsg[_BmeMsgOPCODE_];
    src=pMsg[_BmeMsgSRC_];
    ack=pMsg[_BmeMsgACK_];

    pid.bmeNum=(int) pApiBme->bmeNum;
    pid.portNum=(int) src; 

//  EventLog ("b%ip%i Autonomous message from BME opcode: 0x%x",pid.bmeNum,pid.portNum,opCode);
#ifdef  YING
    printf("pn%d, bn%d,src%d,msg%d \n", pid.portNum, pid.bmeNum,src, pMsg[_BmeMsgSRC_]);
#endif

    switch (opCode)
    {
        
        case EOC_RELAY_DATA_STREAM:         /* EOC_RELAY_DATA_STREAM        */

            if (pid.portNum<=0||pid.portNum>IPOS_MAX_PORT_PER_BME)   /* portNum valid? not: error   */
            {
                printf("NonFATAL ERROR: Error in EOC data stream src \n");
                return IPOS_SUCCESS;    /* non FATAL ERROR: allow other process to continue */
            }

            {
                int len;
                U8  *pData, uid, uidError;
                iposCbEocDataRelay  pCb;
        iposCbError         pCbError;
                tPortParms  *pDPParm;                                                        /* parameters for direct API port */


                uid=pApiBme->port[pid.portNum].uidEocDataRelay;
                uidError=pApiBme->port[pid.portNum].uidError;
                pCb=pApiBme->port[pid.portNum].pCbEocDataRelay;     /* get the callback function    */
        pCbError=pApiBme->port[pid.portNum].pCbError;

/* No.  Maybe no EOC data relay has been registered but an error handler has been
   Sure, it seems strange, but someone might do that and iPOS should support it */
#if 0
                if (pCb==NULL)
                {
                    return IPOS_SUCCESS;                    /* callback is not registered.  */
                }
#endif

                pDPParm=&(pApiBme->pBme->Port[pid.portNum].PortParms);

                len=pDPParm->EocRelayDataStrParms.len;  /* get len and *pData   */
                pData=pDPParm->EocRelayDataStrParms.DataStream;

                if (ack==ACK_SUCCESS && pCb != NULL)
                    pCb(pid, uid,0,len,pData);
        else if (ack != ACK_SUCCESS && pCbError != NULL)
        {
            pCbError(pid, uidError, 0, ack, len, pData );
        }
                return IPOS_SUCCESS;

            }

        case EOC_MSG_RECEIVE:   /* EOC_MSG_RECEIVE          */

            if (pid.portNum<=0||pid.portNum>IPOS_MAX_PORT_PER_BME)   /* portNum valid? not: error   */
            {
                printf("NonFATAL ERROR: Error in EOC msg receive src \n");
                return IPOS_SUCCESS;    /* non FATAL ERROR: allow other process to continue */
            }

            {
                U8  *pData, uid, opCode;
                iposCbEocDataRelay  pCb;
                tPortParms  *pDPParm;                                                        /* parameters for direct API port */

                uid=pApiBme->port[pid.portNum].uidEocMsgRcv;
                pCb=pApiBme->port[pid.portNum].pCbEocMsgRcv;        /* get the callback function    */

                if (pCb==NULL)
                {
                    return IPOS_SUCCESS;                    /* callback is not registered.  */
                }

                pDPParm=&(pApiBme->pBme->Port[pid.portNum].PortParms);


                opCode=pDPParm->EocMsgRecvParms.EocOpcode;  /* get len and *pData   */
                pData=pDPParm->EocMsgRecvParms.DataStream;


                pCb(pid, uid,0,(int) opCode,pData);

                return IPOS_SUCCESS;

            }

            /* Periodic repots          */
        case    GET_COUNTERS:

            if (pid.portNum<=0||pid.portNum>IPOS_MAX_PORT_PER_BME)   /* portNum valid? not: error   */
            {
                printf("NonFATAL ERROR: Error in periodic report \n");
                return IPOS_SUCCESS;    /* non FATAL ERROR: allow other process to continue */
            }

            {
                U8              uid;
                iposCbCntReport pCb;
                tPortParms      *pDPParm;                                                        /* parameters for direct API port */
                ipos_port_counters  *pReport;

                uid=pApiBme->port[pid.portNum].uidCntReport;
                pCb=pApiBme->port[pid.portNum].pCbCntReport;        /* get the callback function    */

                if (pCb==NULL)
                {
                    return IPOS_SUCCESS;                    /* callback is not registered.  */
                }


                pDPParm=&(pApiBme->pBme->Port[pid.portNum].PortParms);

                pReport=(ipos_port_counters *) &(pDPParm->GetCounterParms);             


                pCb(pid, uid,0,IPOS_SUCCESS,pReport);

                return IPOS_SUCCESS;

            }

            /* PM Counters - Periodic Message  */
        case    GET_PM_COUNTERS:
                
            if (pid.portNum<=0||pid.portNum>IPOS_MAX_PORT_PER_BME)   /* portNum valid? not: error       */
            {
                printf("NonFATAL ERROR: Error in periodic report \n");
                return IPOS_SUCCESS;    /* non FATAL ERROR: allow other process to continue     */
            }
               
            {
                U8              uid;
                iposCbPmCounters pCb;
                tPortParms      *pDPParm;         /* parameters for direct API port */
                ipos_pm_counters  *pPmCntr;

                uid=pApiBme->port[pid.portNum].uidPMReport;
                pCb=pApiBme->port[pid.portNum].pCbPmCounters;        /* get the callback function        */
                
                if (pCb==NULL)
                {
                  // UserLog ("iposAutoCmd: Callback not registered"); //Simha
                  return IPOS_SUCCESS;                    /* callback is not registered.      */
                }
                
                pDPParm=&(pApiBme->pBme->Port[pid.portNum].PortParms);
                
                pPmCntr=(ipos_pm_counters *) &(pDPParm->PmCounterParms);             

                pCb(pid, uid, 0, IPOS_SUCCESS, pPmCntr);
                
                return IPOS_SUCCESS;
                
            }

            /* PM Alerts      */
            case GET_PM_ALERT:
    
               if (pid.portNum<=0||pid.portNum>IPOS_MAX_PORT_PER_BME)   /* portNum valid? not: error */
               {
                     printf("NonFATAL ERROR: Error in GET_PM_ALERT \n");
                 return IPOS_SUCCESS;    /* non FATAL ERROR: allow other process to continue */
               }
    
               {
                     U8             uid;
                 iposCbPmAlert pCb;
                     tPortParms     *pDPParm;                                                        /* parameters for direct API port */
                     ipos_pm_alert *pAlert;
    
                     uid=pApiBme->port[pid.portNum].uidPmAlert;
                     pCb=pApiBme->port[pid.portNum].pCbPmAlert;        /* get the callback function  */

                     if (pCb==NULL)
                     {
                         return IPOS_SUCCESS;                    /* callback is not registered.  */
                     }
    
                 pDPParm=&(pApiBme->pBme->Port[pid.portNum].PortParms);
    
                     pAlert=(ipos_pm_alert *) &(pDPParm->PmAlertParms);             
            
                 pCb(pid, uid,0,IPOS_SUCCESS, pAlert);
            
                 return IPOS_SUCCESS;
            
             }


            /* Update reports           */
        case    SYSTEM_STATUS:
            {
                tBmeParms           *pDBParm;                                                        /* parameters for direct API port */
                ipos_system_status  *pStatus;

                iposCbStatusReport  pCb;
                U8                  uidStatus;

                pCb=pApiBme->pCbStatus;
                uidStatus=pApiBme->uidStatus;

                if (pCb==NULL)
                {
                    return IPOS_SUCCESS;                    /* callback is not registered.  */
                }

                pDBParm=&(pApiBme->pBme->BmeParms);

                pStatus=(ipos_system_status *) &(pDBParm->SystemStatusParms);                       

                pCb(pid, uidStatus,0,IPOS_SUCCESS,pStatus);

                return IPOS_SUCCESS;
            }

            case EOC_INTERNAL_TRACE_LOG:         /* EOC_INTERNAL_TRACE_LOG */
            {
                U8  uid, uidError;
                iposCbEocEventLog  pCb;
                iposCbError         pCbError;

                uid=pApiBme->port[pid.portNum].uidEocEventLog;
                uidError=pApiBme->port[pid.portNum].uidError;
                pCb=pApiBme->port[pid.portNum].pCbEocEventLog;     /* get the callback function */
                pCbError=pApiBme->port[pid.portNum].pCbError;

/* No.  Maybe no EOC Event Log callback has been registered but an error handler has been
   Sure, it seems strange, but someone might do that and iPOS should support it */
#if 0
                if (pCb==NULL)
                {
                    return IPOS_SUCCESS;                    /* callback is not registered.  */
                }
#endif

                if (ack==ACK_SUCCESS && pCb != NULL)
                    pCb(pid,&pMsg[_BmeDataLENGTH_]);
                return IPOS_SUCCESS;

            }

             break;

             case HOST_RETRIEVE_BME_CONFIG:
             {

              U8 uid;
              iposCbRetrieveSys pCb;

           // printf("Received HOST_RETRIEVE_BME_CONFIG message from BME\n");
    
               uid=pApiBme->uidStatus;
               pCb=pApiBme->pCbSystemConfig;        /* get the callback function  */

               if (pCb == NULL)
                 return IPOS_SUCCESS;

               if (ack == ACK_SUCCESS) {
                   if (pMsg[_BmeDataLENGTH_] > 0) {
                       pCb(pid,uid,0, IPOS_SUCCESS, &pApiBme->pBme->BmeParms.bmeRxSysProvParms, 
                                                    &pApiBme->pBme->BmeParms.SysProvParms);
                   } 
                 }
                 return IPOS_SUCCESS;
            }
            break;

            case HOST_RETRIEVE_PORT_CONFIG:
            {
              U8             uid;
              iposCbRetrievePort pCb;
              pid.portNum = pMsg[_BmeDataStart_];
           // printf("Received HOST_RETRIEVE_PORT_CONFIG message from BME for port %d\n", pid.portNum);

               uid=pApiBme->port[pid.portNum].uidRetrievePortConfig;
               pCb=pApiBme->port[pid.portNum].pCbPortConfig;        /* get the callback function  */

               if (pCb == NULL) {
                 return IPOS_SUCCESS;
               }

               if (ack == ACK_SUCCESS) {
                 if (pMsg[_BmeDataLENGTH_] > 0) {
                    pCb(pid,uid,0, IPOS_SUCCESS, &pApiBme->pBme->Port[pid.portNum].PortParms.bmeRxPortProfile,
                                                  pApiBme->pBme->Port[pid.portNum].PortParms.pPtrPortProfile);
                 } 
               }
  
               return IPOS_SUCCESS;
            
            }

            break;
                         
            case    PORT_STATUS_BRIEF:
            {
                tPortParms              *pDPParm;               /* parameters for direct API port */
                ipos_port_status_brief  *pStatus;
                U8                       uid;
                iposCbUReport            pCb;   /* update report callback. */

                pCb=pApiBme->port[pid.portNum].pCbUpdateReport;     /* get the callback function	*/
                if (pCb == NULL) {
                    return IPOS_SUCCESS;
                }

                uid=pApiBme->port[pid.portNum].uidUpdateReport;
                pDPParm=&(pApiBme->pBme->Port[pid.portNum].PortParms);
                pStatus=(ipos_port_status_brief *) &(pDPParm->PortStatusBriefParms);                        
                pCb(pid, uid, 0, IPOS_SUCCESS, pStatus);
            }
            break;

        default:
            printf("unknown autonomous msg received.    \n");
            return  IPOS_SUCCESS;

    }   /* switch   */


    return IPOS_SUCCESS;

}

/* handle the status messages: Note: the status message callback functions is in msgBuf */

int  handleIposOptionalCmd(ipos_api_bme *pApiBme, U8 *pMsg)
{

    U8  ack,dest,opCode;                /* for autonomous msg: src and opcode needed for callback */

    ipos_port_id    pid;
    ipos_msg_buf    *pBuf;
    /* dest as index for pBuf. MAX_MSG_BUF>dest>0   */
    iposCbCtl   pCb;  /* callback function for control command  */
    U8  UID;
    U32 uPar;
    int status;

    /* parse the auto command message  and callback  */
    opCode  =pMsg[_BmeMsgOPCODE_];
    dest    =pMsg[_BmeMsgDEST_];
    ack     =pMsg[_BmeMsgACK_];

    /* check the msg is ready for callback  */
    if (dest<=0||dest>=IPOS_MAX_MSG)
    {
        printf("FATAL ERROR: Destination is %d in handleIposOptionalCmd\n", dest);
        return  IPOS_ERROR_MSG_SOURCE;

    }

    pBuf = iposMsgFindMsg(dest);

    if (pBuf->cbSet!=IPOS_MSG_CALLBACK_SET)
    {
        if (pBuf == NULL)
          printf("FATAL ERROR: Logic error with iposMsgFindMsg in handleIposOptionalCmd, dest = %d\n", dest);
    else
          printf("FATAL ERROR: Callback not set for destination %d in handleIposOptionalCmd\n", dest );
        return  IPOS_ERROR_CALLBACK_NOT_SET;
    }

    pCb=(iposCbCtl) iposGetCallback(pBuf,&pid,&UID,&uPar);


    iposMsgFree(pBuf);  /* no buffer needed: free   */



    if (pCb==NULL)
    {
        return  IPOS_SUCCESS;           /* no callback needed   */
    }


    if (ack==ACK_SUCCESS)    status=IPOS_SUCCESS;
    else                    status= (int) ack;

    switch (opCode)
    {
        
        case GET_OPCMD_STATUS:
            if (pid.portNum<=0||pid.portNum>IPOS_MAX_PORT_PER_BME)   /* portNum valid? not: error   */
            {
                printf("NonFATAL ERROR: Error in periodic report \n");
                return IPOS_SUCCESS;    /* non FATAL ERROR: allow other process to continue */
            }

            {
                tPortParms              *pDPParm;                                                        /* parameters for direct API port */
                ipos_opCmd_status       *pReport;


                if (pCb==NULL)
                {
                    return IPOS_SUCCESS;                    /* callback is not registered.  */
                }

                pDPParm=&(pApiBme->pBme->Port[pid.portNum].PortParms);

                pReport=(ipos_opCmd_status *) &(pDPParm->opCmdResults);                     

                pCb(pid, UID, uPar,status,pReport);
                return IPOS_SUCCESS;
            }
    }

    return IPOS_SUCCESS;
}

/* handle the status messages: Note: the status message callback functions is in msgBuf */

int  iposStatusCmd(ipos_api_bme *pApiBme, U8 *pMsg)
{

    U8  ack,dest,opCode;                /* for autonomous msg: src and opcode needed for callback */

    ipos_port_id    pid;
    ipos_msg_buf    *pBuf;
    /* dest as index for pBuf. MAX_MSG_BUF>dest>0   */
    iposCbCtl   pCb;  /* callback function for control command  */
    U8  UID;
    U32 uPar;
    int status;

    /* parse the auto command message  and callback  */
    opCode  =pMsg[_BmeMsgOPCODE_];
    dest    =pMsg[_BmeMsgDEST_];
    ack     =pMsg[_BmeMsgACK_];

    /* check the msg is ready for callback  */
    if (dest<=0||dest>=IPOS_MAX_MSG)
    {
        printf("FATAL ERROR: Destination is %d in iposStatusCmd\n", dest);
        return  IPOS_ERROR_MSG_SOURCE;

    }

    pBuf = iposMsgFindMsg(dest);

    if ((pBuf == NULL) || (pBuf->cbSet!=IPOS_MSG_CALLBACK_SET))
    {
        if (pBuf == NULL)
          printf("FATAL ERROR: Logic error with iposMsgFindMsg in iposStatusCmd, dest = %d\n", dest);
    else
          printf("FATAL ERROR: Callback not set for destination %d in iposStatusCmd\n", dest );
        return  IPOS_ERROR_CALLBACK_NOT_SET;
    }

    pCb=(iposCbCtl) iposGetCallback(pBuf,&pid,&UID,&uPar);


    iposMsgFree(pBuf);  /* no buffer needed: free   */



    if (pCb==NULL)
    {
        return  IPOS_SUCCESS;           /* no callback needed   */
    }


    if (ack==ACK_SUCCESS)    status=IPOS_SUCCESS;
    else                    status= (int) ack;

    switch (opCode)
    {
        
        case    PORT_STATUS_BRIEF:

            if (pid.portNum<=0||pid.portNum>IPOS_MAX_PORT_PER_BME)   /* portNum valid? not: error   */
            {
                printf("NonFATAL ERROR: Error in periodic report \n");
                return IPOS_SUCCESS;    /* non FATAL ERROR: allow other process to continue */
            }

            {
                tPortParms      *pDPParm;                                                        /* parameters for direct API port */
                ipos_port_status_brief  *pStatus;


                if (pCb==NULL)
                {
                    return IPOS_SUCCESS;                    /* callback is not registered.  */
                }

                pDPParm=&(pApiBme->pBme->Port[pid.portNum].PortParms);

                pStatus=(ipos_port_status_brief *) &(pDPParm->PortStatusBriefParms);                        

                pCb(pid, UID,uPar,status, pStatus);

                return IPOS_SUCCESS;
            }


        case    PORT_STATUS_EXTENDED:

            if (pid.portNum<=0||pid.portNum>IPOS_MAX_PORT_PER_BME)   /* portNum valid? not: error   */
            {
                printf("NonFATAL ERROR: Error in periodic report \n");
                return IPOS_SUCCESS;    /* non FATAL ERROR: allow other process to continue */
            }

            {
                tPortParms      *pDPParm;                                                        /* parameters for direct API port */
                ipos_port_status    *pStatus;


                if (pCb==NULL)
                {
                    return IPOS_SUCCESS;                    /* callback is not registered.  */
                }

                pDPParm=&(pApiBme->pBme->Port[pid.portNum].PortParms);

                pStatus=(ipos_port_status *) &(pDPParm->PortStatusExtParms);                        

                pCb(pid, UID,uPar,status,pStatus);

                return IPOS_SUCCESS;
            }


        case    SYSTEM_STATUS:

            {
                tBmeParms           *pDBParm;                                                        /* parameters for direct API port */
                ipos_system_status  *pStatus;


                if (pCb==NULL)
                {
                    return IPOS_SUCCESS;                    /* callback is not registered.  */
                }

                pDBParm=&(pApiBme->pBme->BmeParms);

                pStatus=(ipos_system_status *) &(pDBParm->SystemStatusParms);                       

                pCb(pid, UID,uPar,status,pStatus);

                return IPOS_SUCCESS;
            }

            /* Periodic repots          */
        case    GET_COUNTERS:

            if (pid.portNum<=0||pid.portNum>IPOS_MAX_PORT_PER_BME)   /* portNum valid? not: error   */
            {
                printf("NonFATAL ERROR: Error in periodic report \n");
                return IPOS_SUCCESS;    /* non FATAL ERROR: allow other process to continue */
            }

            {
                tPortParms      *pDPParm;                                                        /* parameters for direct API port */
                ipos_port_counters  *pReport;


                if (pCb==NULL)
                {
                    return IPOS_SUCCESS;                    /* callback is not registered.  */
                }

                pDPParm=&(pApiBme->pBme->Port[pid.portNum].PortParms);

                pReport=(ipos_port_counters *) &(pDPParm->GetCounterParms);                     

                pCb(pid, UID,uPar,status,pReport);

                return IPOS_SUCCESS;
            }

            /* PM Counters - Status Request Message  */
            case    GET_PM_COUNTERS:

               if (pid.portNum<=0||pid.portNum>IPOS_MAX_PORT_PER_BME)   /* portNum valid? not: error */
              {
                printf("NonFATAL ERROR: Error in GET_PM_COUNTERS \n");
                  return IPOS_SUCCESS;    /* non FATAL ERROR: allow other process to continue */
            }
    
              {
                tPortParms      *pDPParm;                     /* parameters for direct API port */
                ipos_pm_counters  *pPmCntr;
    
                if (pCb==NULL)
                {
                 return IPOS_SUCCESS;                    /* callback is not registered.  */
                }

                pDPParm=&(pApiBme->pBme->Port[pid.portNum].PortParms);
    
                pPmCntr=(ipos_pm_counters *) &(pDPParm->PmCounterParms);                     

                pCb(pid, UID,uPar,status,pPmCntr);
    
                return IPOS_SUCCESS;
            }
            /* Update reports           */
        case    UPDATED_REPORTS_ENABLE: 

            if (pid.portNum<=0||pid.portNum>IPOS_MAX_PORT_PER_BME)   /* portNum valid? not: error   */
            {
                printf("NonFATAL ERROR: Error in periodic report \n");
                return IPOS_SUCCESS;    /* non FATAL ERROR: allow other process to continue */
            }

            {
                tPortParms      *pDPParm;                                                        /* parameters for direct API port */
                ipos_port_counters  *pReport;


                if (pCb==NULL)
                {
                    return IPOS_SUCCESS;                    /* callback is not registered.  */
                }

                pDPParm=&(pApiBme->pBme->Port[pid.portNum].PortParms);

                pReport=(ipos_port_counters *) &(pDPParm->GetCounterParms);                     

                pCb(pid, UID,uPar,status,pReport);

                return IPOS_SUCCESS;
            }

        case    DEVICE_VERSIONS:

            {
                tPortParms      *pDPParm;                                                        /* parameters for direct API port */
                ipos_bme_ver    *pReport;


                if (pCb==NULL)
                {
                    return IPOS_SUCCESS;                    /* callback is not registered.  */
                }

                pDPParm=&(pApiBme->pBme->Port[pid.portNum].PortParms);

                pReport=(ipos_bme_ver *) &(pDPParm->DeviceVerParms);                        

                pCb(pid, UID,uPar,status,pReport);

                return IPOS_SUCCESS;
            }

        case    GET_NE_SNR_ATTN:    

            if (pid.portNum<=0||pid.portNum>IPOS_MAX_PORT_PER_BME)   /* portNum valid? not: error   */
            {
                printf("NonFATAL ERROR: Error in periodic report \n");
                return IPOS_SUCCESS;    /* non FATAL ERROR: allow other process to continue */
            }

            {
                tPortParms      *pDPParm;                                                        /* parameters for direct API port */
                ipos_port_nesnrattn     *pReport;


                if (pCb==NULL)
                {
                    return IPOS_SUCCESS;                    /* callback is not registered.  */
                }

                pDPParm=&(pApiBme->pBme->Port[pid.portNum].PortParms);

                pReport=(ipos_port_nesnrattn *) &(pDPParm->NeSnrAttn);                      

#ifdef  NOTI            
                copySnrAttnToOamp (pReport,pid);            
#endif

                pCb(pid, UID,uPar,status,pReport);

                return IPOS_SUCCESS;
            }
        case GET_OPCMD_STATUS:
            if (pid.portNum<=0||pid.portNum>IPOS_MAX_PORT_PER_BME)   /* portNum valid? not: error   */
            {
                printf("NonFATAL ERROR: Error in periodic report \n");
                return IPOS_SUCCESS;    /* non FATAL ERROR: allow other process to continue */
            }
            {
                tPortParms              *pDPParm;                                                        /* parameters for direct API port */
                ipos_opCmd_status       *pReport;


                if (pCb==NULL)
                {
                    return IPOS_SUCCESS;                    /* callback is not registered.  */
                }

                pDPParm=&(pApiBme->pBme->Port[pid.portNum].PortParms);

                pReport=(ipos_opCmd_status *) &(pDPParm->opCmdResults);                     

                pCb(pid, UID,uPar,status,pReport);
                return IPOS_SUCCESS;
            }
    }
    return IPOS_SUCCESS;
}




/*************************************************************
        
        stub parser to be tested
        
        
*************************************************************/


int  iposStatusCmdExt(ipos_api_bme *pApiBme, U8 *pMsg)
{
    return IPOS_SUCCESS;
}


int  iposCtrlCmdExt(ipos_api_bme *pApiBme, U8 *pMsg)
{
    return IPOS_SUCCESS;
}


int  iposTstCmd(ipos_api_bme *pApiBme, U8 *pMsg)
{
    U8 dest, ack, UID, opCode;
    U32 uPar;
    int status = IPOS_SUCCESS;
    ipos_msg_buf    *pBuf;
    iposCbCtl       pCb;  /* callback function for control command  */
    ipos_port_id    pid;

    /* dest serves as the index to the msgBuf   */
    dest   = pMsg[_BmeMsgDEST_];
    opCode = pMsg[_BmeMsgOPCODE_];
    ack    = pMsg[_BmeMsgACK_];

    /* check the msg is ready for callback  */
    if (dest<=0||dest>=IPOS_MAX_MSG)
    {
        printf("FATAL ERROR: Destination is %d in iposCtrlCmd\n", dest);
        return  IPOS_ERROR_MSG_SOURCE;
    }

    pBuf = iposMsgFindMsg(dest);

    if ((pBuf == NULL) || (pBuf->cbSet!=IPOS_MSG_CALLBACK_SET))
    {
        if (pBuf == NULL)
            printf("FATAL ERROR: Logic error with iposMsgFindMsg in iposCtrlCmd, dest = %d\n", dest);
        else
            printf("FATAL ERROR: Callback not set for destination %d in iposCtrlCmd\n", dest );
        
        return (IPOS_ERROR_CALLBACK_NOT_SET);
    }


    pCb=(iposCbCtl) iposGetCallback(pBuf,&pid,&UID,&uPar);
    
    iposMsgFree(pBuf);

    if ( pCb )
    {

        if ( (opCode == DETECT_SIGNALS) && (ack == ACK_SUCCESS) && (pMsg[_BmeDataLENGTH_] == 4) )
        {
            pCb (pid, UID, uPar, status, &pMsg[_BmeDataStart_]);
        }
        else
        {
            // We want to show the failure code if BME NACK it.
            //
            if (ack != ACK_SUCCESS)
                status = ack;
            pCb (pid, UID, uPar, status, NULL);
        }
    }

    return IPOS_SUCCESS;
}
