/*
================================ COPYRIGHT ================================
The contents of this file are subject to the VTech Informations Ltd. License
of VT-OS Ver. 1.1 operating system (the "License"); you may not use this 
file except in compliance with the License.  

Software distributed under the License is distributed on an "AS IS" basis, 
WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License 
for the specific language governing rights and limitations under the License.
  
The Original Code is VT-OS Ver. 1.1 Operating System, released 
on October 1st, 1999
	
The Initial Developer of the Original Code is VTech Informations Ltd.  All 
codes are Copyright (C) VTech Informations Ltd. 1999.  All Rights Reserved.
===========================================================================
*/

/*
===========================================================================
File        :   msg.c
Author(s)   :   Brian Lee
Company     :   VTech Informations Ltd.
Project     :   Helio 
Date:	    :   October 1st, 1999
Purpose:	:   Message queue control
Revision    :   1.1
Note        :   20/7/99  add MsgAppendMsgReplaceInt() for ISR
27/7/98  add MsgAppendInt() for ISR
27/7/98  add MsgAppendInt() for ISR
25/6/98  release (BL)
24/3/98  Create by Brian Lee (BL)
===========================================================================
*/              


#define __MESSAGE__

#include "stdafx.h"
#include "QTYPE.H"
#include "MSG.H"
#include "ERRMGR.H"
#include "intc.h"
#include "sylang.h"

/* message queue */

MsgQueueType msgQueue;

/* private function prototype */

//static  void    MsgCopyMessage(MsgType *, MsgType *);


/***************************************************************************
*  Prototype   void MsgAppendMsg(void (*ptr_fct)(), WORD msgID, WORD para1,
*				WORD para2, void * msgPBP)
*  Purpose     Append an message to the end of queue
*  Scope       OS
*  InPara      components of the struct MsgType
*  OutPara     None
*  Return      None
*  Comment     Make sure the queue has been created and not full
***************************************************************************/
void MsgAppendMsg(void (*ptr_fct)(), WORD msgID, WORD para1, WORD para2, void * msgPBP)
{
	MsgType msg;
#ifdef PC_SIM
	msg.ptr_fct = (void (__cdecl *)(void *))(ptr_fct);
#else
	msg.ptr_fct = (ptr_fct);
#endif
	msg.msgID   = msgID;
	msg.para1   = para1;
	msg.para2   = para2;
	msg.msgPBP  = msgPBP;
	
	MsgAppend(msg, &msgQueue);
}
/***************************************************************************
*  Prototype   void MsgAppendMsgReplaceInt(void (*ptr_fct)(), WORD msgID, WORD para1,
*				WORD para2, void * msgPBP)
*  Purpose     Replace/Append an message to the end of queue
*  Scope       Interrupt
*  InPara      components of the struct MsgType
*  OutPara     None
*  Return      None
*  Comment     Make sure the queue has been created and not full
***************************************************************************/

void MsgAppendMsgReplaceInt(void (*ptr_fct)(), WORD msgID, WORD para1, WORD para2, void * msgPBP)
{
	MsgType msg;
	
	UWORD count, front;
	
#ifdef PC_SIM
	msg.ptr_fct = (void (__cdecl *)(void *))(ptr_fct);
#else
	msg.ptr_fct = (ptr_fct);
#endif
	msg.msgID   = msgID;
	msg.para1   = para1;
	msg.para2   = para2;
	msg.msgPBP  = msgPBP;
	
	count = msgQueue.count;
	front = msgQueue.front;
	
	while(count) {
		if((msgQueue.message[front].ptr_fct == msg.ptr_fct) &&
			(msgQueue.message[front].msgID == msg.msgID))
		{
            msgQueue.message[front] = msg;
            return;
        }
        front=(front+1) % MSG_QUEUE_SIZE;
        count--;
    }
	MsgAppendInt(msg, &msgQueue);
}


/***************************************************************************
*  Prototype   void MsgClearAppMsg
*  Purpose     Clear application message in message queue
*  Scope       OS
*  InPara      None
*  OutPara     None
*  Return      None
*  Comment     Make sure the queue has been created and not full
***************************************************************************/
void MsgClearAppMsg()
{
	
	UWORD count, front;
	
	count = msgQueue.count;
	front = msgQueue.front;
	
	while(count) {
        if(( (UWORD)msgQueue.message[front].ptr_fct & (UWORD) 0xF0000000) == 0x10000000)
        {
            msgQueue.message[front].ptr_fct = NULL;
        }
        front=(front+1) % MSG_QUEUE_SIZE;
        count--;
    }
}


/***************************************************************************
*  Prototype   void MsgAppendMsgInt(void (*ptr_fct)(), WORD msgID, WORD para1,
*				WORD para2, void * msgPBP)
*  Purpose     Append an message to the end of queue
*  Scope       Interrupt
*  InPara      components of the struct MsgType
*  OutPara     None
*  Return      None
*  Comment     Make sure the queue has been created and not full
*              This rountine is safe to be called from Interrupt level
***************************************************************************/
void MsgAppendMsgInt(void (*ptr_fct)(), WORD msgID, WORD para1, WORD para2, void * msgPBP)
{
	MsgType msg;
	
#ifdef PC_SIM
	msg.ptr_fct = (void (__cdecl *)(void *))ptr_fct;
#else
	msg.ptr_fct = ptr_fct;
#endif
	msg.msgID   = msgID;
	msg.para1   = para1;
	msg.para2   = para2;
	msg.msgPBP  = msgPBP;
	
	MsgAppendInt(msg, &msgQueue);
}

/***************************************************************************
*  Prototype   void MsgQueueCreate(MsgQueueType *Q)
*  Purpose     Initialize the message queue to empty
*  Scope       OS
*  InPara      None
*  OutPara     *Q - the queue is clear
*  Return      None
*  Comment     None
***************************************************************************/
void MsgQueueCreate(MsgQueueType *Q)
{
    Q->count = 0;
    Q->front = 0;
    Q->rear = -1;
}

/***************************************************************************
*  Prototype   BOOLEAN MsgQueueEmpty(MsgQueueType *Q)
*  Purpose     Check if the message queue is empty
*  Scope       OS
*  InPara      *Q - queue to be checked
*  OutPar     None
*  Return      TRUE if queue empty
*  Comment     None
***************************************************************************/
BOOLEAN MsgQueueEmpty(MsgQueueType *Q)
{
    if(Q->count==0) return TRUE;
    return FALSE;
}

/***************************************************************************
*  Prototype   BOOLEAN MsgQueueFull(MsgQueueType *Q)
*  Purpose     Check if the message queue is full
*  Scope       OS
*  InPara      *Q - queue to be checked
*  OutPara     None
*  Return      TRUE if queue full
*  Comment     None
***************************************************************************/
BOOLEAN MsgQueueFull(MsgQueueType *Q)
{
    if(Q->count==MSG_QUEUE_SIZE) return TRUE;
    return FALSE;
}

/***************************************************************************
*  Prototype   void MsgAppend(MsgType msg, MsgQueueType *Q)
*  Purpose     Append an message to the end of queue
*  Scope       OS
*  InPara      msg - message to be added
*  OutPara     *Q - the message is stored in last entry of the queue
*  Return      None
*  Comment     Make sure the queue has been created and not full
***************************************************************************/
void MsgAppend(MsgType msg, MsgQueueType *Q)
{
    DISABLE_INTERRUPT;
    if (MsgQueueFull(Q)) ErrDisplay(SYSTR12);
    else {
        Q->count++;
        Q->rear=(Q->rear+1) % MSG_QUEUE_SIZE;
        Q->message[Q->rear] = msg;
		//        MsgCopyMessage(&(Q->message[Q->rear]), &msg);
    }
    ENABLE_INTERRUPT;
}

/***************************************************************************
*  Prototype   void MsgAppendInt(MsgType msg, MsgQueueType *Q)
*  Purpose     Append an message to the end of queue
*  Scope       Interrupt
*  InPara      msg - message to be added
*  OutPara     *Q - the message is stored in last entry of the queue
*  Return      None
*  Comment     Make sure the queue has been created and not full
*              This rountine is safe to be called from Interrupt level
***************************************************************************/
void MsgAppendInt(MsgType msg, MsgQueueType *Q)
{
    if (!MsgQueueFull(Q))
    {
        Q->count++;
        Q->rear=(Q->rear+1) % MSG_QUEUE_SIZE;
        Q->message[Q->rear] = msg;
		//        MsgCopyMessage(&(Q->message[Q->rear]), &msg);
    }
}

/***************************************************************************
*  Prototype   BOOLEAN MsgServe(MsgType *msgP, MsgQueueType *Q)
*  Purpose     Get a message from the head of queue
*  Scope       OS
*  InPara      *Q - the queue to be served
*  OutPara     *eventP - contain the first entry in the message queue
*  Return      FALSE if queue empty
*  Comment     Make sure the queue has been created
***************************************************************************/
BOOLEAN MsgServe(MsgType *msgP, MsgQueueType *Q)
{
    if (MsgQueueEmpty(Q))
    {
		return FALSE;
	}
    else {
		DISABLE_INTERRUPT;
        Q->count--;
		//        MsgCopyMessage(msgP, &(Q->message[Q->front]));
		*msgP = Q->message[Q->front];
        Q->front=(Q->front+1) % MSG_QUEUE_SIZE;
		ENABLE_INTERRUPT;
    }
    return TRUE;
}

/***************************************************************************
*  Prototype   void MsgCopyMessage(MsgType *msgDest, MsgType *msgSrc)
*  Purpose     Copy the content of message from source to destination
*  Scope       Internal
*  InPara      *eventSrc - source
*  OutPara     *eventDest - destination
*  Return      None
*  Comment     None
***************************************************************************/
/*void MsgCopyMessage(MsgType *msgDest, MsgType *msgSrc)
{
msgDest->ptr_fct = msgSrc->ptr_fct;
msgDest->msgID   = msgSrc->msgID;
msgDest->para1 = msgSrc->para1;
msgDest->para2 = msgSrc->para2;
msgDest->msgPBP = msgSrc->msgPBP;
}
*/
/***************************************************************************
*  Prototype   void MsgDecode(MsgQueueType *msgQ)
*  Purpose     Dispatch the message to the correspond handling routine
*  Scope       OS
*  InPara      *msgQ - the queue to be serve
*  OutPara     None
*  Return      None
*  Comment     None
***************************************************************************/
void MsgDecode(MsgQueueType *msgQ)
{
	
#define INT_MSG_FCT_START 0x30000000
#define INT_MSG_FCT_END   0x3FFFFFFF
	
    MsgType message;
	
    /* dispatch the message to the corresponding service routine */
    if (MsgServe(&message, msgQ))
    {
#ifdef xxxxxxxxxxxxxxxxx
        if( (UWORD) message.ptr_fct >= INT_MSG_FCT_START)
			if( (UWORD) message.ptr_fct < INT_MSG_FCT_END)
			{  /* interrupt message call */
                printf("\n Msg, appid = %d ", message.para2);
                SysLoadInterruptPageTable(message.para2);
                printf("\nCall to addr %08x ", message.ptr_fct);
			}
#endif
			if(message.ptr_fct)
				message.ptr_fct((MsgType *) &message);
    }
}
