/*
================================ 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        :   eventmgr.c
Author(s)   :   Brian Lee
Company     :   VTech Informations Ltd.
Project     :   Helio 
Date:	    :   October 1st, 1999
Purpose:	:   Event Manger
Revision    :   1.1
Note        :   None
===========================================================================
*/              


#define __EVENT_MANAGER__

#include "stdafx.h"
#include "QTYPE.H"
#include "EVENTMGR.H"
#include "MSG.H"
#include "ERRMGR.H"
#include "pr31700s.h"
#include "pr31700c.h"
#include "intc.h"
#include "dev_pwr.h"
#include "kernel.h"
#include "sio.h"
#include "sylang.h"
#include "system.h"

#ifdef PC_SIM
extern BOOL m_bIsExit;
extern HWND m_wndEmuDlg;
#endif

#define MAX_EVT_HANDLE 		16

/* event queue */
EvtQueueType evtQueue;

BOOLEAN (*EvtHandle[MAX_EVT_HANDLE])();
BOOLEAN (*EvtEventHanlder)();
BOOLEAN EvtDummy(void);
UWORD 	UartMgrChkBufBytes();
UWORD 	UartMgrChkBufBytesDummy();

extern	MsgQueueType	msgQueue;
extern UWORD	(*UartMgrChkUartANumBytes)();

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

/***************************************************************************
*	Prototype	void EvtGetEvent(EvtType *eventP)
*	Purpose 	To get the system event from the event queue
*	Scope		Application
*	InPara		None
*	OutPara 	*eventP - contain the first entry in the event queue
*	Return		None
*	Comment 	The system goto doze mode if there is no data in the event
*				queue and message queue
***************************************************************************/


#define SOFT_RESET ((int*)0x9fc10000)

void EvtGetEvent(EvtType *eventP)
{
	void (*func_call) ();
    register UWORD  *ptr;
    
	
#ifdef PC_SIM
	MSG msg;
#endif
	
	do {
		MsgDecode(&msgQueue);
		
		DIS_GBL_INT;
        if(EvtQueueEmpty(&evtQueue) && MsgQueueEmpty(&msgQueue) && UartMgrChkUartANumBytes() == 0)
        {
            if ((CheckBatteryEmpty() == FALSE) && (sio_download_driver == 0))
                CpuDoze();
			if (CheckBatteryEmpty() != FALSE) 
			{
				EvtQueueCreate(&evtQueue);
				MsgQueueCreate(&msgQueue);
                HwSystemEmgPowerOff();
                DIS_GBL_INT;                    //991010
                ptr    = BOOT_INFO_ADDRESS;
                ptr[0] = BOOT_WARM_PATT;        /* indicate ward start */
                ptr      = SOFT_RESET;
                CpuChangeSpeedInt(CPU_CLK_37M);
                func_call= (void*)ptr;
                func_call();
                while (1);
			}
		}
		ENA_GBL_INT;
	} while ((EvtQueueEmpty(&evtQueue)) && !EvtEventHanlder());
	
	EvtServe(eventP, &evtQueue);   
}

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

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

/***************************************************************************
*	Prototype	void EvtAppendEvt(WORD eventType, WORD eventID, WORD para1,
*				WORD para2, void *evtPBP)
*	Purpose 	Append an event to the end of queue
*	Scope		OS
*	InPara		event - event to be added
*	OutPara 	*Q - the event is stored in last entry of the queue
*	Return		None
*	Comment 	Make sure the queue has been created and not full
***************************************************************************/
void EvtAppendEvt(WORD eventType, WORD eventID, WORD para1, WORD para2, void *evtPBP)
{
	EvtType event;
	
	event.eventType = eventType;
	event.eventID	= eventID;
	event.para1 	= para1;
	event.para2 	= para2;
	event.evtPBP	= evtPBP;
	
	if (EvtQueueFull(&evtQueue)) 
		ErrDisplay(SYSTR16);
	else 
	{
		evtQueue.count++;
		evtQueue.rear=(evtQueue.rear+1) % EVT_QUEUE_SIZE;
		evtQueue.event[evtQueue.rear] = event;
	}
}

/***************************************************************************
*	Prototype	void EvtAppend(EvtType event, EvtQueueType *Q)
*	Purpose 	Append an event to the end of queue
*	Scope		OS
*	InPara		event - event to be added
*	OutPara 	*Q - the event is stored in last entry of the queue
*	Return		None
*	Comment 	Make sure the queue has been created and not full
***************************************************************************/
void EvtAppend(EvtType event, EvtQueueType *Q)
{
	if (EvtQueueFull(Q)) ErrDisplay(SYSTR16);
	else {
		Q->count++;
		Q->rear=(Q->rear+1) % EVT_QUEUE_SIZE;
		Q->event[Q->rear] = event;
	}
}

/***************************************************************************
*	Prototype	void EvtServe(EvtType *eventP, EvtQueueType *Q)
*	Purpose 	Get an event from the head of queue
*	Scope		OS
*	InPara		*Q - the queue to be served
*	OutPara 	*eventP - contain the first entry in the event queue
*	Return		None
*	Comment 	Make sure the queue has been created
*				Output NULL_EVENT if queue empty
***************************************************************************/
void EvtServe(EvtType *eventP, EvtQueueType *Q)
{
	if (EvtQueueEmpty(Q)) eventP->eventType = (WORD)NULL;
	else {
		Q->count--;
		*eventP = Q->event[Q->front];
		Q->front=(Q->front+1) % EVT_QUEUE_SIZE;
	}
}

/***************************************************************************
*  Prototype   void EvtAppendEvtReplaceByTypeOnly(WORD eventType, WORD eventID, WORD para1,
*				WORD para2, void *evtPBP)
*	Purpose 	Append an unique event to the end of queue
*	Scope		OS
*	InPara		event - event to be added
*	OutPara 	*Q - the event is stored in last entry of the queue
*	Return		None
*	Comment 	Make sure the queue has been created and not full
***************************************************************************/
void EvtAppendEvtReplaceByTypeOnly(WORD eventType, WORD eventID, WORD para1, WORD para2, void *evtPBP)
{
	EvtType event;
	UWORD count, front;
	
	event.eventType = eventType;
	event.eventID	= eventID;
	event.para1 	= para1;
	event.para2 	= para2;
	event.evtPBP	= evtPBP;
	
	count = evtQueue.count;
	front = evtQueue.front;
	
	while(count)
	{
        if((evtQueue.event[front].eventType == event.eventType))
		{
			evtQueue.event[front] = event;
			return;
		}
		front=(front+1) % EVT_QUEUE_SIZE;
		count--;
	}
	
	// no same event in the queue, append it into queue
	if (EvtQueueFull(&evtQueue))
		ErrDisplay(SYSTR16);
	else
	{
		evtQueue.count++;
		evtQueue.rear=(evtQueue.rear+1) % EVT_QUEUE_SIZE;
		
		evtQueue.event[evtQueue.rear]=event;
	}
}


/***************************************************************************
*	Prototype	void EvtAppendEvtReplace(WORD eventType, WORD eventID, WORD para1,
*				WORD para2, void *evtPBP)
*	Purpose 	Append an unique event to the end of queue
*	Scope		OS
*	InPara		event - event to be added
*	OutPara 	*Q - the event is stored in last entry of the queue
*	Return		None
*	Comment 	Make sure the queue has been created and not full
***************************************************************************/
void EvtAppendEvtReplace(WORD eventType, WORD eventID, WORD para1, WORD para2, void *evtPBP)
{
	EvtType event;
	UWORD count, front;
	
	event.eventType = eventType;
	event.eventID	= eventID;
	event.para1 	= para1;
	event.para2 	= para2;
	event.evtPBP	= evtPBP;
	
	count = evtQueue.count;
	front = evtQueue.front;
	
	while(count)
	{
		if((evtQueue.event[front].eventType == event.eventType) &&
			(evtQueue.event[front].eventID == event.eventID))
		{
			evtQueue.event[front] = event;
			return;
		}
		front=(front+1) % EVT_QUEUE_SIZE;
		count--;
	}
	
	// no same event in the queue, append it into queue
	if (EvtQueueFull(&evtQueue))
		ErrDisplay(SYSTR16);
	else
	{
		evtQueue.count++;
		evtQueue.rear=(evtQueue.rear+1) % EVT_QUEUE_SIZE;
		
		evtQueue.event[evtQueue.rear]=event;
	}
}
/***************************************************************************
*	Prototype	BOOLEAN EvtAddEventHandler(BOOLEAN *fct())
*	Purpose 	add an event handle function
*	Scope		OS
*	InPara		fct - pointer to the added function
*	OutPara 	TRUE if success, FALSE if no empty slot
*	Return		None
*	Comment 	max. handle number defined by MAX_EVT_HANDLE
***************************************************************************/
BOOLEAN EvtAddEventHandler(BOOLEAN (*fct)())
{
	WORD h_index = MAX_EVT_HANDLE;
	
	do {
		h_index--;
		if(!EvtHandle[h_index]) {
			EvtHandle[h_index] = fct;
            EvtEventHanlder = EvtHandler;
			return TRUE;
		}
	} while(h_index);
	return FALSE;
}
/***************************************************************************
*	Prototype	BOOLEAN EvtRemoveEventHandler(void *fct())
*	Purpose 	remove an event handle function
*	Scope		OS
*	InPara		fct - pointer to the function to be removed
*	OutPara 	TRUE if success, FALSE if fucntion not found
*	Return		None
*	Comment 	None
***************************************************************************/
BOOLEAN EvtRemoveEventHandler(BOOLEAN (*fct)())
{
	WORD h_index = MAX_EVT_HANDLE;
	WORD h_num = 0;
	
	do {
		h_index--;
		if(EvtHandle[h_index] == fct) EvtHandle[h_index] = NULL;
		else if(EvtHandle[h_index]) h_num++;
	} while(h_index);
	
	if(!h_num) EvtEventHanlder = EvtDummy;
	return FALSE;
}

/***************************************************************************
*	Prototype	BOOLEAN EvtHandler(void)
*	Purpose 	process the added event handler
*	Scope		OS
*	InPara		None
*	OutPara 	TRUE if has event
*				FALSE if no event
*	Return		None
*	Comment 	None
***************************************************************************/
BOOLEAN EvtHandler(void)
{
	WORD h_index = MAX_EVT_HANDLE;
	BOOLEAN hasEvent = FALSE;
	
	do {
		h_index--;
		if(EvtHandle[h_index]) hasEvent |= EvtHandle[h_index]();
	} while(h_index);
	return hasEvent;
}

/***************************************************************************
*	Prototype	void EvtInitHandler(void)
*	Purpose 	Init the EvtHandle array
*	Scope		OS
*	InPara		None
*	OutPara 	None
*	Return		None
*	Comment 	None
***************************************************************************/
void EvtInitHandler(void)
{
	WORD h_index = MAX_EVT_HANDLE;
	
	do {h_index--; EvtHandle[h_index] = NULL;} while(h_index);
	EvtEventHanlder = EvtDummy;
}

/***************************************************************************
*	Prototype	BOOLEAN EvtDummy(void)
*	Purpose 	dummy function
*	Scope		OS
*	InPara		None
*	OutPara 	None
*	Return		FALSE
*	Comment 	None
***************************************************************************/
BOOLEAN EvtDummy(void)
{
	return FALSE;
}


