/*
================================ 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        :   psyncfx.c
Author(s)   :   Kenny Ng
Company     :   VTech Informations Ltd.
Project     :   Helio 
Date:	    :   October 1st, 1999
Purpose:	:   application c file
Revision    :   1.1
Note        :   None
===========================================================================
*/              

#include "uartmgr.h"
#include "syncfx.h"
#include "comctrl.h"
#include "pdasync.h"
#include "synctout.h"
#include "combuf.h"
#include "app.h"
#include "lcddebug.h"
#include "sysetup.h"
#include "uart.h"
#include "kernel.h"
#include "alaunch.h"
#include "alarmgr.h"
#include "dev_pwr.h"

//#define DEBUG_MODEM

#define TOTAL_SYNC_APP  7


extern BYTE buf[];
WORD hport;
USHORT sync_total_fail;
USHORT sync_total_ok;
void (*ComFctPtr)(UBYTE);
void (*WaitReturnFct)(UBYTE);
void (*TimeOutFct)(UBYTE);
void (*BufferDoneFct)(UBYTE);
void SyncTimeOut();

void DeleteFailRecord();
void SetToDoAlarm();
void SetAnnAlarm();
void SetSchAlarm();

UWORD en_timer;
UWORD timeout_byte_count;
UWORD timeout_timer=0;
WORD is_sync = 0;
BYTE set_ann_alm;
BYTE set_sch_alm;
BYTE set_todo_alm;

MatInfoList *mat_info_ptr[TOTAL_SLOT];
extern BYTE os_upgrade;
extern BYTE need_del;
extern DatabaseID del_dbid;
extern RecordID del_recid;
WORD rec_mode = 0;

void ExpenseDatabaseInit();

#ifdef DEBUG
extern BYTE buf[50];
#endif

BYTE timeoutmsg[30];
#ifdef EL32
#undef EL32
#define EL32(x)         (x <<24 | (x &0xff00) <<8 | (x &0xff0000) >>8 | x>>24)
#endif

void SetWaitReturnFct( void (*fct))
{
    /* function will be called after PortWaitForChar or PortWaitForLength */
	
	//if (fct == NULL)
	//	ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
    WaitReturnFct = fct;
	/* to do: if fct != NULL, should enable the timer, else disable the timer */
}

void SetComHandleEvent( void (*fct))
{
	/* function will be called by a char recieved */
	if (fct)
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
    ComFctPtr = fct;
}

void SetBufferDoneFct( void (*fct))
{
	BufferDoneFct = fct;
}

void SetTimeOutFct(void *fct)
{
	TimeOutFct = fct;
}

void SyncNormalAbort(UBYTE x)
{
	
}

void UpdateDisp()
{
	BYTE *list_text;
	BYTE object_type;
	List *list_ptr;
	
    PCSyncListSetScrollbar();
    ListDrawList(LIST_SYNC_LOG);
}

BOOLEAN SyncInitPort()
{
	UWORD sync_speed;
	hport = 0xFFFFFFFF;
	
	if(ComOpenPort(UART_A, &hport) != TRUE)
	{
		/* cannot open the port */
		return FALSE;
	}
	
	SySetupGetSyncSpeedSettings(&sync_speed);
	
	switch (sync_speed)
	{
	case 115200:
		sync_speed = UART_BAUD115200;
		break;
	case 57600:
		sync_speed = UART_BAUD57600;
		break;
	case 38400:
		sync_speed = UART_BAUD38400;
		break;
	case 19200:
		sync_speed = UART_BAUD19200;
		break;
	case 9600:
		sync_speed = UART_BAUD9600;
		break;
	case 4800:
		sync_speed = UART_BAUD4800;
		break;
	case 2400:
		sync_speed = UART_BAUD2400 ;
		break;
	case 1200:
		sync_speed = UART_BAUD1200;
		break;
	default:
		sync_speed = UART_BAUD57600;
	}
	
	ComConfigPort(hport, sync_speed, UART_DATABIT8|UART_PARITY_NONE|UART_STOPBIT1);
	/* capture the port */
	ComSetDataMode(COM_DATA_BIN);
	ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
	return TRUE;
}

Err DataTotalArcRecord(DatabaseID dbid, UWORD *total_rec)
{
	UWORD sblock;
	USHORT i, block;
	RecordHeader *rec_ptr;
	DBHeader *db_ptr;
	
	sblock = 0xFFFFFFFF;
	for(i=0;i<TOTAL_SLOT;i++)
		if ( (MemoryFindStartBlock(mat_info_ptr[i], dbid, &block)) == TRUE)
		{
			sblock = MakeSBlock(i, block);
			break;
		}
		
		if(sblock == 0xFFFFFFFF) return ERR_DATA_DB_MISS;
		
        db_ptr = (DBHeader*) SBlockAddr(sblock);
        rec_ptr = (RecordHeader*) (SBlockAddr(sblock) + db_ptr->length);
		*total_rec = 0;
		while(1)
		{
			if(!NormRec(rec_ptr))
				if(!FragRec(rec_ptr))      /* not a fragment */
					if(rec_ptr->size != DATA_CHUNK_END)
						*total_rec = (*total_rec) + 1;
					else
						break;
					rec_ptr = (RecordHeader*)((UWORD)rec_ptr + rec_ptr->size);  /* next record */
                    if (((UWORD)rec_ptr - SBlockAddr(sblock)) >= (BLOCK_SIZE - RECHEADER_SIZE))  /* next record on next block */
					{
                        if(MemoryNextBlock(mat_info_ptr[SBlockMat(sblock)], block, &block) != TRUE)
							break;
						sblock = MakeSBlock(SBlockMat(sblock), block);
                        rec_ptr = (RecordHeader *) SBlockAddr(sblock);
					}
					else
						if(rec_ptr->size == DATA_CHUNK_END) /* end of records in this block, any for next block? */
						{
							if(MemoryNextBlock(mat_info_ptr[SBlockMat(sblock)], block, &block) != TRUE)
								break;
							sblock = MakeSBlock(SBlockMat(sblock), block);
							rec_ptr = (RecordHeader *) SBlockAddr(sblock);
						}
		}
		return TRUE;
}


Err DataBuildArchiveSortTable(UWORD sblock, USHORT sort_field, SortTableLnkPtr *sort_table)
{
	UWORD i,j,tmp;
	BOOLEAN is_sort;
	UWORD total_rec;
	UWORD block_addr, db_block;
	USHORT block;
	DBHeader *db_ptr;
	RecordHeader *rec_ptr;
	BOOLEAN is_move;
	DatabaseID dbid;
	
	dbid = mat_info_ptr[SBlockMat(sblock)]->mat[SBlockBlock(sblock)].id;
	if (DataTotalArcRecord(dbid, &total_rec) != TRUE)
	{
		
		return ERR_DATA_DB_MISS;
	}
	
	if((*sort_table = (SortTableLnkPtr) qmalloc(sizeof(SortTableLnk)))==NULL)
		return ERR_DATA_NO_MEM;
	
	(*sort_table)->next_table = NULL;
	(*sort_table)->sort_field = sort_field;
	if (sort_field == DB_NO_SORT)
		is_sort = FALSE;
	else
		is_sort = TRUE;
	
	db_block = sblock;
	block_addr = SBlockAddr(sblock);         /* block address */
	block = SBlockBlock(sblock);             /* block number */
	
	(*sort_table)->total_entry = total_rec+3;
	if(((*sort_table)->rec_id = (UWORD*) qmalloc((total_rec + 3 )* sizeof(UWORD))) == NULL)
	{
		qfree(sort_table);
		return ERR_DATA_NO_MEM;
	}
	
	if(((*sort_table)->cat = (UBYTE*) qmalloc((total_rec + 3 )* sizeof(UBYTE))) == NULL)
	{
		qfree((*sort_table)->rec_id);
		qfree(sort_table);
		return ERR_DATA_NO_MEM;
	}
	
	for(i=0;i<total_rec+3;i++)
		(*sort_table)->rec_id[i] = 0xFFFFFFFF;
	
	/* find all record's id */
	db_ptr = (DBHeader*) block_addr;
	rec_ptr = (RecordHeader*) (block_addr + db_ptr->length);
	i=0;
	
	while(1)
	{
		if(!NormRec(rec_ptr))
			if(!FragRec(rec_ptr))      /* not a category record & fragment */
				if( rec_ptr->rec_id < 0x80000fff  )  /* archive && cat record olny*/
					if(rec_ptr->size != DATA_CHUNK_END)
					{
						(*sort_table)->rec_id[i++] = rec_ptr->rec_id;
						DataSortData(db_block, rec_ptr->rec_id, rec_ptr->cat, sort_table, is_sort,NULL);
					}
					else
						break;
					
					rec_ptr = (RecordHeader*)((UWORD)rec_ptr + rec_ptr->size);  /* next record */
                    if (((UWORD)rec_ptr - SBlockAddr(sblock)) >= (BLOCK_SIZE - RECHEADER_SIZE))  /* next record on next block */
					{
                        if(MemoryNextBlock(mat_info_ptr[SBlockMat(sblock)], block, &block) != TRUE)
							break;
						sblock = MakeSBlock(SBlockMat(sblock), block);
                        rec_ptr = (RecordHeader *) SBlockAddr(sblock);
					}
					else
						if(rec_ptr->size == DATA_CHUNK_END) /* end of records in this block, any for next block? */
						{
							if(MemoryNextBlock(mat_info_ptr[SBlockMat(sblock)], block, &block) != TRUE)
								break;
							sblock = MakeSBlock(SBlockMat(sblock), block);
							rec_ptr = (RecordHeader *) SBlockAddr(sblock);
						}
	}
	
	return TRUE;
}


void DispMsg(USHORT msg_id)
{
	WORD total_item, top_item_num;
	USHORT id;
	
	BYTE *ptr;
	BYTE *ptr2;
	BYTE item[12][25] = { SYNC_EMAIL, SYNC_PHONEBOOK, SYNC_SCHEDULER, SYNC_VOICE, SYNC_TODO, SYNC_ANN, SYNC_SKETCH, SYNC_EXPENSE, SYNC_MEMO, SYNC_SYSTEM, SYNC_BACKUP, SYNC_SYNC};
	List    *list_ptr;
	BYTE    object_type;
	
	id = msg_id;
	
	if(id>=20)
		id -= 20;
	
	ptr2 = ptr = (BYTE*) (&item[id]);
	
	ptr += strlen(ptr2);
	
	if(msg_id>=20)
	{
		strcpy(ptr, FAIL);
		sync_total_fail++;
	}
	else
	{
		strcpy(ptr, OK);
		sync_total_ok++;
	}
	
	ListGetNumOfItems(LIST_SYNC_LOG, (USHORT*)&total_item);
	ListInsertItem(LIST_SYNC_LOG, (USHORT)total_item, ptr2);
	
	FormGetObjectPointer(LIST_SYNC_LOG, &object_type, (void**)&list_ptr);
	if (list_ptr->list_total_num_items <= 4)
		list_ptr->list_top_item_num = 0;
	else if (list_ptr->list_top_item_num >= (list_ptr->list_total_num_items - 4))
		list_ptr->list_top_item_num = list_ptr->list_total_num_items - 4;
	else list_ptr->list_top_item_num ++;
	
	ListDrawList(LIST_SYNC_LOG);
}


void DispStr(BYTE *msg)
{
	WORD total_item, top_item_num;
	USHORT id;
	List    *list_ptr;
	BYTE    object_type;
	
	
	ListGetNumOfItems(LIST_SYNC_LOG, (USHORT*)&total_item);
	ListInsertItem(LIST_SYNC_LOG, (USHORT)total_item, msg);
	
	FormGetObjectPointer(LIST_SYNC_LOG, &object_type, (void**)&list_ptr);
	if (list_ptr->list_total_num_items <= 4)
		list_ptr->list_top_item_num = 0;
	else if (list_ptr->list_top_item_num >= (list_ptr->list_total_num_items - 4))
		list_ptr->list_top_item_num = list_ptr->list_total_num_items - 4;
	else list_ptr->list_top_item_num ++;
	
	ListDrawList(LIST_SYNC_LOG);
}


void DispSyncDate()
{
	RTM date;
	BYTE buf[50];
	USHORT total_item;
	BYTE date_setting, time_setting;
	CountrySettings country_setting;
	BYTE tmp_buf[20];
	BYTE pos = 0;
	
	date_setting = SYSETUP_MDY;
	time_setting = SYSETUP_12HR_DISPLAY;
	if( SySetupGetCountrySettings(&country_setting) == TRUE)
	{
		date_setting = country_setting.date_fmt;
		time_setting = country_setting.time_fmt;
	}
	
	RtcGetTime(&date);
	
	if(date_setting == SYSETUP_DMY)
		strcpy(tmp_buf, SYNCSTR1);
	else
		strcpy(tmp_buf, SYNCSTR2);
	pos = strlen(tmp_buf);
	if(time_setting == SYSETUP_12HR_DISPLAY)
		strcpy(tmp_buf + pos, SYNCSTR3);
	else
		strcpy(tmp_buf + pos, SYNCSTR4);
	
	RtcFormatDate(&date, tmp_buf, buf);
	
	ListGetNumOfItems(LIST_SYNC_LOG, &total_item);
	ListInsertItem(LIST_SYNC_LOG, total_item, buf);
	UpdateDisp();
}

/***********************************************************************
SyncReq
************************************************************************/
void SyncStart()
{
	SHORT i;
	BYTE *temp_buf;
	
	sync_total_fail = 0;
	sync_total_ok = 0;
	rec_mode = 0;
	
	temp_buf = (BYTE*) qmalloc(TRAN_PACKET_SIZE);	/* pre-allocate the block for quicker response to app-install */
	pfree(temp_buf);
	
	for(i=0;i<TOTAL_SLOT;i++)
	{
        mat_info_ptr[i] = (MatInfoList*) MemoryGetMatPtr(i);
	}
	
	ComClosePort(hport);
	SyncInitPort();     
	
	i = 0x70;
	while(i--);
	
	PortSendChar(ST_FLG);    /* send start flag */
	SetTimeOutFct(SyncNormalAbort);
	SetWaitReturnFct(SyncStart2);
	PortWaitForChar(ST_ACK, ST_NAK, ST_ACK, TRUE);
}

void TmrDum()
{
	CheckPdaPwr();
}

void TmrTimeOut()
{
	if(timeout_byte_count == 0)
	{
        if(rec_mode == 0)
        {
			SysEnableHotSyncButton();
			DisTimeOutTmr();
			is_sync = 0;
        }
	}
	rec_mode = timeout_byte_count = 0;
}

void EnTmr()
{
	
	if(en_timer == 0)
		en_timer = TmrIntEnable(50*1000,TmrDum);
	
}

void EnTimeOutTmr()
{
	
	if(timeout_timer == 0)
		timeout_timer = TmrIntEnable(7*1000,TmrTimeOut);
	
	timeout_byte_count = 0;
	
}

void DisTmr()
{
	if(en_timer != 0)
	{
		TmrIntDisable(en_timer);
		en_timer = 0;
	}
}

void DisTimeOutTmr()
{
	if(timeout_timer != 0)
	{
		TmrIntDisable(timeout_timer);
		timeout_timer = 0;
		timeout_byte_count = 0;
	}
}


void SyncStart2(UBYTE x )
{
    BYTE    object_type = 0x70;
    Scrollbar   *scroll_ptr;
	
	OffEL();
	while(object_type--);
	//    CpuChangeSpeed(CPU_CLK_75M);
	CpuChangeSpeed(CPU_CLK_37M);
	BatteryWarningSetEnableStatus(FALSE);
	AlarmMgrEnable(FALSE);
	DataCloseAllDB();
	is_sync = 1;
	EnTmr();
	EnTimeOutTmr();
	DisBufTmr();
	SysDisableHotSyncButton();
	
	if(need_del)
        DeleteFailRecord();
	
	os_upgrade = 0;
	SetWaitReturnFct(NULL);
	
	if(bcomtimeout == TRUE)
        (*TimeOutFct);
	else
	{
		if(x != ST_ACK)   /* ST_NAK */
		{
#ifdef DEBUG
			LcdPrintf("\nget NAK from PC");
#endif
			// todo abort sync
		}
		strcpy(timeoutmsg, PCTIMEOUT);
		SetTimeOutFct(SyncNormalAbort);
		SetComHandleEvent(SyncStateInit);
	}
	
	FormGetObjectPointer(SCROLLBAR_SYNC_LOG, &object_type, (void**)&scroll_ptr);
	scroll_ptr->scrollbar_attr.scrollbar_visible = FALSE;
	ScrollbarEraseScrollbar(SCROLLBAR_SYNC_LOG);
	
	
}

/*******************************************
Initialization state
********************************************/
void SyncStateInit(UBYTE x)
{		
	BufferRemove(1);
	SetTimeOutFct(SyncNormalAbort);   /* reset the time out timer */
	switch(x)
	{
	case OS_VER_REQ:
		SyncSendOSVer();
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case USER_REQ:
		SyncUserReq();
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case USERWR_REQ:	     
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case CLKSET_REQ:
		SetClock();
		break;
	case CLK_REQ:
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case IDLE_MODE_REQ:
		SetComHandleEvent(SyncStateIdle);
		PortSendChar(IDLE_MODE_ACK);
		break;
	case CLEAR_CRASH:
		SysSetCrashStatus(0);
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case SHOW_STATE_RDY:
		DispStateReady();
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case SHOW_STATE_1:
		DispState1();
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case SHOW_STATE_2:
		DispState2();
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case SHOW_STATE_3:
		DispState3();
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case LOG_MSG_EM:
	case LOG_MSG_PB:
	case LOG_MSG_SCH:
	case LOG_MSG_VOX:
	case LOG_MSG_TD:
	case LOG_MSG_ANN:
	case LOG_MSG_SK:
	case LOG_MSG_EXP:
	case LOG_MSG_MEMO:
	case LOG_MSG_SYS:
	case LOG_MSG_BACKUP:
	case LOG_MSG_SYNC:	
	case LOG_MSG_EM_F:
	case LOG_MSG_PB_F:
	case LOG_MSG_SCH_F:
	case LOG_MSG_VOX_F:
	case LOG_MSG_TD_F:
	case LOG_MSG_ANN_F:
	case LOG_MSG_SK_F:
	case LOG_MSG_EXP_F:
	case LOG_MSG_MEMO_F:
	case LOG_MSG_SYS_F:
	case LOG_MSG_BACKUP_F:
	case LOG_MSG_SYNC_F:	
		DispMsg((UBYTE)(*(UBYTE*)&x) - (UBYTE)LOG_MSG_EM);
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case LOG_MSG_DATE:
		DispSyncDate();
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case LOG_CLR_MSG:
		ListDeleteAllItems(LIST_SYNC_LOG);
		PCSyncListSetScrollbar();
		ListDrawList(LIST_SYNC_LOG);
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;	
	case CRASH_ENQ:
		if(SysGetCrashStatus())
	           PortSendChar(CRASH_YES);
		else
	           PortSendChar(CRASH_NO);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);	           
		break;
	case UP_SYSTEM:
		os_upgrade = 1;
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case UP_SYSTEM_CONFIRM:
		ListDeleteAllItems(LIST_SYNC_LOG);
		PCSyncListSetScrollbar();
		ListDrawList(LIST_SYNC_LOG);
		DispStr(SYSUPDATE);        
		if(os_upgrade == 1)
			BatChkMainLevel();
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
	default:             
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);			
      }
}

void SyncSendOSVer()
{
	BYTE buf[50];
	BYTE *ptr;
	SHORT cs = 0;
	UWORD ver_len;
	UWORD pack_len;
	UWORD i;
	
	SysGetOSVersionNo(buf);
	ver_len = strlen(buf);
	
	pack_len = ver_len + 3;  /* len + NULL + cs */
	ptr = (BYTE*) &pack_len;
	
	PortSendChar(OS_VER_ACK);
	
	for(i=0;i<sizeof(pack_len);i++)
		PortSendChar(*ptr++);
	
	for(i=0;i<ver_len;i++)
	{
		cs ^= buf[i];
		PortSendChar(buf[i]);
	}
	
	cs ^= 0;
	PortSendChar(0);
	
	ptr = (BYTE*) &cs;
	
	PortSendChar(ptr[0]);
	PortSendChar(ptr[1]);
}


void SetClock()
{
	SetWaitReturnFct(SetClock2);
    PortWaitForLength(sizeof(RTM) + 2);
    PortSendChar(CLKSET_ACK);
}

void SetClock2(UBYTE x)
{
    RTM 	*t;
    
    t = (RTM*) sync_buf;
    RtcSetTime(t);
    SetComHandleEvent(SyncStateInit);
    BufferEmpty();
    PortSendChar(ACK);
}

void SyncUserReq()
{
	DatabaseID dbid;
	RecordID rec_id;
	BYTE *lname, *fname, *buf, *ptr;
	UWORD i, total_rec, byte_read, length;
	BOOLEAN found;
	USHORT cs;
	
	lname = NULL;
	fname = NULL;
	buf = NULL;
	found = FALSE;
	
	if(DataFindDB(SYSETUPDB, &dbid) != TRUE)
	{
#ifdef DEBUG
		LcdPrintf("\nCannot found SysDB ");
#endif
	}
	else
	{
		DataOpenDB(dbid, 0, OPEN_RW);
		DataTotalRecord(dbid, &total_rec);
		for(i=0;i<total_rec;i++)
		{
			DataOpenRecord(dbid, i, &rec_id, NULL);
			if(DataGetField(dbid, rec_id, 0, &buf, &byte_read)== TRUE)
			{
				if (buf[0] == OWNINFO)  /* field 0 = OWNINFO for user info record */
				{
					DataGetField(dbid, rec_id, 1, &lname, &byte_read);
					DataGetField(dbid, rec_id, 2, &fname, &byte_read);
					found = TRUE;
				}
				if(byte_read)
					qfree(buf);
			}
			DataCloseRecord(dbid, rec_id);
			if (found)
				break;
		}
		DataCloseAllDB();//(dbid);
	}
	
	PortSendChar(ACK);
	length = 2+2;   /* cs +'\0' + '\0' */
	if(found)
	{
		if(fname)
			length += strlen(fname);
		if(lname)
			length += strlen(lname);
	}
	
	ptr = (BYTE*) &length;
	for(i=0;i<4;i++)
		PortSendChar(ptr[i]);
	cs = 0;
	if(lname)
	{
		for(i=0;i<strlen(lname);i++)
		{
			cs ^= lname[i];
			PortSendChar(lname[i]);
		}
	}
	cs ^= 0;
	PortSendChar('\0');
	
	if(fname)
	{
		for(i=0;i<strlen(fname);i++)
		{
			cs ^= fname[i];
			PortSendChar(fname[i]);
		}
	}
	cs ^= 0;
	PortSendChar('\0');
	
	ptr = (BYTE*)&cs;
	
	PortSendChar(ptr[0]);
	PortSendChar(ptr[1]);
}


/*******************************************
Idle state
********************************************/
void SyncStateIdle(UBYTE x)
{
	USHORT 	total_item;
    BYTE     object_type;
    List     *list_ptr;
	
    BufferRemove(1);
    CheckPdaPwr();
    
    SetTimeOutFct(SyncNormalAbort);   /* reset the time out timer */
    switch(x)
    {
	case IDLE_MODE_REQ:
		PortSendChar(IDLE_MODE_ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case DBENQ_MODE_REQ:
		SetComHandleEvent(SyncStateDBEnq);
		PortSendChar(DBENQ_MODE_ACK);
		break;
	case DBUP_MODE_REQ:
		SetComHandleEvent(SyncStateDBUp);
		PortSendChar(DBUP_MODE_ACK);
		break;
	case NEWAPP_MODE_REQ:
		SetComHandleEvent(SyncStateNewApp);
		PortSendChar(NEWAPP_MODE_ACK);
		break;
	case SYSBK_MODE_REQ:
		PortSendChar(SYSBK_MODE_REQ);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case CLEAR_CRASH:
		SysSetCrashStatus(0);
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case SHOW_STATE_RDY:
		DispStateReady();
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case SHOW_STATE_1:
		DispState1();
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case SHOW_STATE_2:
		DispState2();
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case SHOW_STATE_3:
		DispState3();
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;               
	case TERM_MODE_REQ:
		SetComHandleEvent(SyncStateTerm);
		ListGetNumOfItems(LIST_SYNC_LOG, &total_item);
		DisTmr();
		DisTimeOutTmr();
		DisBufTmr();
		is_sync = 0;
		SysEnableHotSyncButton();
		if(sync_total_fail)
			ListInsertItem(LIST_SYNC_LOG, total_item, SYNCFAIL);
		else
		{
			if(sync_total_ok == TOTAL_SYNC_APP)
				ListInsertItem(LIST_SYNC_LOG, total_item, SYNCEND);
			else
				ListInsertItem(LIST_SYNC_LOG, total_item, SYNCEND);
		}
		BatteryWarningSetEnableStatus(TRUE);
		AlarmMgrEnable(TRUE);
		DispStateReady();
		CpuChangeSpeed(CPU_CLK_37M);
		ComClosePort(hport);
		SyncInitPort();
		FormGetObjectPointer(LIST_SYNC_LOG, &object_type, (void**)&list_ptr);
		if (list_ptr->list_total_num_items <= 4)
			list_ptr->list_top_item_num = 0;
		else if (list_ptr->list_top_item_num >= (list_ptr->list_total_num_items - 4))
			list_ptr->list_top_item_num = list_ptr->list_total_num_items - 4;
		else list_ptr->list_top_item_num ++;
		UpdateDisp();
		PortSendChar(TERM_MODE_ACK);
		break;
	case MSG_LOG_REQ:
		SetComHandleEvent(SyncMsgLog);
		PortSendChar(MSG_LOG_ACK);
		break;
	case LOG_MSG_EM:
	case LOG_MSG_PB:
	case LOG_MSG_SCH:
	case LOG_MSG_VOX:
	case LOG_MSG_TD:
	case LOG_MSG_ANN:
	case LOG_MSG_SK:
	case LOG_MSG_EXP:
	case LOG_MSG_MEMO:
	case LOG_MSG_SYS:
	case LOG_MSG_BACKUP:
	case LOG_MSG_SYNC:
	case LOG_MSG_EM_F:
	case LOG_MSG_PB_F:
	case LOG_MSG_SCH_F:
	case LOG_MSG_VOX_F:
	case LOG_MSG_TD_F:
	case LOG_MSG_ANN_F:
	case LOG_MSG_SK_F:
	case LOG_MSG_EXP_F:
	case LOG_MSG_MEMO_F:
	case LOG_MSG_SYS_F:
	case LOG_MSG_BACKUP_F:
	case LOG_MSG_SYNC_F:
		DispMsg((UBYTE)(*(UBYTE*)&x) - (UBYTE)LOG_MSG_EM);
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case LOG_MSG_DATE:
		DispSyncDate();
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case LOG_CLR_MSG:
		ListDeleteAllItems(LIST_SYNC_LOG);
		ListDrawList(LIST_SYNC_LOG);
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case CRASH_ENQ:
		if(SysGetCrashStatus())
          		PortSendChar(CRASH_YES);
		else
          		PortSendChar(CRASH_NO);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case CLKSET_REQ:
		SetClock();
		break;
	case SET_ANN_ALM:
		set_ann_alm = 1;
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case SET_TODO_ALM:
		set_todo_alm = 1;
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case SET_SCH_ALM:
		set_sch_alm = 1;
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	default:
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);			
      } 
}


/*******************************************
Log message
********************************************/
BYTE logmsg_mode;
WORD logmsg_len;
BYTE logmsg_data[40];
void SyncMsgLog(UBYTE x)
{
	logmsg_mode = x; 
    BufferRemove(1);
    SetTimeOutFct(SyncNormalAbort);   /* reset the time out timer */
    
    switch(x)
    {
	case LOG_MSG_EM:
	case LOG_MSG_PB:
	case LOG_MSG_SCH:
	case LOG_MSG_VOX:
	case LOG_MSG_TD:
	case LOG_MSG_ANN:
	case LOG_MSG_SK:
	case LOG_MSG_EXP:
	case LOG_MSG_MEMO:
	case LOG_MSG_SYS:
	case LOG_MSG_BACKUP:
	case LOG_MSG_SYNC:	
	case LOG_MSG_EM_F:
	case LOG_MSG_PB_F:
	case LOG_MSG_SCH_F:
	case LOG_MSG_VOX_F:
	case LOG_MSG_TD_F:
	case LOG_MSG_ANN_F:
	case LOG_MSG_SK_F:
	case LOG_MSG_EXP_F:
	case LOG_MSG_MEMO_F:
	case LOG_MSG_SYS_F:
	case LOG_MSG_BACKUP_F:
	case LOG_MSG_SYNC_F:	
		DispMsg((UBYTE)(*(UBYTE*)&x) - (UBYTE)LOG_MSG_EM);
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case LOG_MSG_DATE:
		DispSyncDate();
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case LOG_CLR_MSG:
		ListDeleteAllItems(LIST_SYNC_LOG);
		ListDrawList(LIST_SYNC_LOG);
		PortSendChar(ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case IDLE_MODE_REQ:
		PortSendChar(IDLE_MODE_ACK);
		SetComHandleEvent(SyncStateIdle);
		break;
	default:
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);		       		
    }
}

void SyncGetLogMsg()
{
	SetWaitReturnFct(SyncGetLogMsg2);
	PortSendChar(MSG_ACK);
	PortWaitForChar(MSG_SEQ, MSG_SEQ, MSG_SEQ, TRUE);
}

void SyncGetLogMsg2(UBYTE x)
{
	SetWaitReturnFct(SyncGetLogMsg3);
	PortWaitForLength(4);  /* length */
}

void SyncGetLogMsg3(UBYTE x)
{
	logmsg_len = *(WORD*) sync_buf;
	SetWaitReturnFct(SyncGetLogMsg4);
	PortWaitForLength(logmsg_len + 4);
}

void SyncGetLogMsg4(UBYTE x)
{
	WORD i;
	SetWaitReturnFct(NULL);
	for(i=0;i<logmsg_len;i++)
	{
		if(i < 39)
			logmsg_data[i] = sync_buf[i+4];
		else
			break;
	}
	logmsg_data[i+4] = 0;
	BufferEmpty();
#ifdef DEBUG
	LcdPrintf(logmsg_data);
#endif
	SetComHandleEvent(SyncStateDBEnq);
}

/*******************************************
DBEnq state
********************************************/
void SyncStateDBEnq(UBYTE x)
{
	BufferRemove(1);
	
    switch(x)
    {
	case DBENQ_MODE_REQ:
		PortSendChar(DBENQ_MODE_ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case GENINF_REQ:
		SyncDBGenInfo();
		break;
	case DBINFO_REQ:
		SyncDBInfo();
		break;
	case RECINFO_REQ:
		SyncRecInfoReq();
		break;
	case SCHRECINFO_REQ:
		SyncSchRecInfoReq();
		break;
	case MODIREC_REQ:
		SyncReadRecInf();
		break;
	case RECDATA_REQ:
		SyncReadRec();
		break;
	case RECFIELD_REQ:
		SyncReadField();
		break;
	case RECARCINFO_REQ:
		SyncRecArcInfoReq();
		break;
	case APP_REQ:
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);			      
		break;
	case IDLE_MODE_REQ:
		PortSendChar(IDLE_MODE_ACK);
		SetComHandleEvent(SyncStateIdle);
		break;
	default:
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);			
	}      
}


void DeleteFailRecord()
{
	if(need_del)
    {
		DataCloseAllDB();
		if(DataOpenDB(del_dbid, DB_NO_SORT, OPEN_RW)==TRUE)
		{
			DataDeleteRecord(del_dbid, del_recid, FALSE);
			DataCloseAllDB();
		}
		need_del = 0;
    }
}

/*******************************************
DBUpdate state
********************************************/
void SyncStateDBUp(UBYTE x)
{
	BufferRemove(1);
    SetTimeOutFct(SyncNormalAbort);   /* reset the time out timer */
	
    if(need_del)
       	DeleteFailRecord();
	
    switch(x)
    {
	case DBUP_MODE_REQ:
		PortSendChar(DBUP_MODE_ACK);
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case DELREC_REQ:
		SyncRecDel();
		break;
	case ADDREC_REQ:
		SyncRecAdd();
		break;
	case ADDREC_LARGE_REQ:
		SyncRecAddLarge();
		break;
	case ADDCAT_REQ:
		SyncCatAdd();
		break;
	case DELDB_REQ:
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);
		break;
	case NEWDB_REQ:
		SyncDBNew();            
		break;
	case NEWREC_REQ:
		SyncRecNew();
		break;
	case MAX_RECID_REQ:
		SyncSetMaxRecID();
		break;
	case REASIGN_RECID_REQ:
		SyncReasignRecID();
		break;
	case SCH_CHG_APPNUM_REQ:
		SyncChgSchApptNum();
		break;
	case IDLE_MODE_REQ:
		SetComHandleEvent(SyncStateIdle);
		PortSendChar(IDLE_MODE_ACK);
		break;
	default:
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);			       
	}
}

extern BYTE install_revert;
/*******************************************
New app state
********************************************/
void SyncStateNewApp(UBYTE x)
{
	BufferRemove(1);
    SetTimeOutFct(SyncNormalAbort);   /* reset the time out timer */
	
    if(install_revert)
		UndoInstall();
    
    switch(x)
    {
	case NEWAPP_REQ:
		SyncNewApp();
		break;
	case IDLE_MODE_REQ:
		PortSendChar(IDLE_MODE_ACK);
		SetComHandleEvent(SyncStateIdle);
		break;
	default:
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);			                
    }
}


/*******************************************
Terminate state
********************************************/
void SyncStateTerm(UBYTE x)
{
	BufferRemove(1);
    SetTimeOutFct(SyncNormalAbort);   /* reset the time out timer */
    
    switch(x)
    {
	case END_FLG:
		BufferEmpty();
		PortSendChar(END_ACK);
		SetComHandleEvent(SyncStateInit);
		break;
	case IDLE_MODE_REQ:
		PortSendChar(IDLE_MODE_ACK);
		SetComHandleEvent(SyncStateIdle);
		break;
	default:
		ComCapture(hport, COM_MODE_CHAR, 0, 0, NULL);					                
    }
}


//////////////////////////////////////////////
/*        Database Enquiry              */

/********************************************
General info. enq
*********************************************/
void SyncDBGenInfo()
{
	
}

void SyncTimeOut()
{
}

void SyncDBInfo()
{
	BYTE dbname[32];
	BYTE *com_buf;
	
	SetComHandleEvent(NULL);
	PortSendChar(DBINFO_ACK);
	SetWaitReturnFct(SyncDBInfo2);
	PortWaitForChar(DBID_REQ, DBID_REQ, DBID_REQ, TRUE);
}

void SyncDBInfo2(UBYTE x)
{
	SetTimeOutFct(SyncNormalAbort);
	SetWaitReturnFct(SyncDBInfo3);
	PortWaitForChar(0x00, 0x00, 0x00, TRUE);        /* wait for db name */
}

void SyncDBInfo4(UBYTE x);
void SyncDBInfo3(UBYTE x)
{
	BYTE dbname[32];
	DatabaseID dbid;
	UWORD len;
	BYTE *dbheader;
	BYTE *data;
	SHORT cs;
	USHORT i, block;
	
	strcpy(dbname, sync_buf);      /* find the db */
	SetTimeOutFct(SyncNormalAbort);
	
	if(DataFindDB(dbname, &dbid) != TRUE)
	{
		SetWaitReturnFct(SyncDBInfo4);
		PortWaitForLength(2);
		PortSendChar(NAK);
		BufferEmpty();
#ifdef DEBUG
		LcdPrintf("\ndatabase not found");
#endif
	}                         
	else
	{
		for(i=0;i<TOTAL_SLOT;i++)     /* find all slot for the db */
		{
			if(MemoryFindStartBlock(mat_info_ptr[i], dbid, &block) == TRUE)
				if(BlockType(mat_info_ptr[i]->mat[block].attribute) == MAT_BLOCK_DB_REC)
					break;
		}
		if(i>=TOTAL_SLOT)
		{
#ifdef DEBUG
			LcdPrintf("unknown err");
#endif
			PortSendChar(NAK);
			BufferEmpty();
		}
		else
		{
#ifdef DEBUG
			LcdPrintf("DB OK" );
#endif
			PortSendChar(DBINFO_DATA_ACK);
			dbheader = (BYTE*) BlockAddr(mat_info_ptr[i], block);
			len = 4 + ((DBHeader*) dbheader)->length + 2;  /* dbid + header + cs */
			
			data = (BYTE*) &len;
			for(i=0;i<4;i++)
				PortSendChar(data[i]);
			
			cs = 0;
			
			data = (BYTE*)&dbid;
			for(i=0;i<4;i++)
			{
				cs ^= data[i];
				PortSendChar(data[i]);
			}
			
			for(i=0;i<len - 6;i++)
			{
				cs ^= dbheader[i];
				PortSendChar(dbheader[i]);
			}
			data = (BYTE*) &cs;
			PortSendChar(data[0]);
			BufferEmpty();
			//                  SetWaitReturnFct(SyncDBInfo4);
			SetWaitReturnFct(NULL);
			SetComHandleEvent(SyncStateDBEnq);
			PortSendChar(data[1]);
			//                  PortWaitForChar(ACK, ACK, ACK, TRUE);        /* wait for db name */
			//                  PortWaitForLength(1);
			//                  SetWaitReturnFct(NULL);
		}
	}
}

void SyncDBInfo4(UBYTE x)
{
	SetWaitReturnFct(NULL);
	SetComHandleEvent(SyncStateDBEnq);
	PortSendChar(ACK);
}

void SetToDoAlarm()
{
	AppID appid;
	AlarmEventHit *evt_hit;
	
	if(set_todo_alm)
	{
		
		if( SysGetAppID(TODO1, &appid) != TRUE)
			return;
		evt_hit = (AlarmEventHit*) pmalloc(sizeof(AlarmEventHit));
		evt_hit->type = 0;
		evt_hit->rec_id = 0;
		evt_hit->reference = 0;
		SysRunMode1App(appid, LAUNCH_CMD_ALARM_HIT, evt_hit);
		set_todo_alm = 0;
		
	}
}

void SetAnnAlarm()
{
	AppID appid;
	AlarmEventHit *evt_hit;
	
	if(set_ann_alm)
	{
		
		if( SysGetAppID(ANN1, &appid) != TRUE)
			return;
		
		evt_hit = (AlarmEventHit*) pmalloc(sizeof(AlarmEventHit));
		evt_hit->type = 0;
		evt_hit->rec_id = 0;
		evt_hit->reference = 0;
		SysRunMode1App(appid, LAUNCH_CMD_ALARM_HIT, evt_hit);
		set_ann_alm = 0;
	}
}

void SetSchAlarm()
{
	AppID appid;
	AlarmEventHit *evt_hit;
	
	if(set_sch_alm)
	{
		
		if( SysGetAppID(SCHEDULER1, &appid) != TRUE)
			return;
		
		evt_hit = (AlarmEventHit*) pmalloc(sizeof(AlarmEventHit));
		evt_hit->type = 0;
		evt_hit->rec_id = 0;
		evt_hit->reference = 0;
		
		
		SysRunMode1App(appid, LAUNCH_CMD_ALARM_HIT, evt_hit);
		
		set_sch_alm = 0;
	}
}
