/*
+-------------------------------------------------------------------+
| PROJECT: MMI-Framework (8445)		$Workfile:: mfw_bt_flash.c			$|
| $Author:: Thomas Sommer			$Revision::  1						$|
| CREATED: 03.05.04					$Modtime:: 22.04.04 11:07			$|
| STATE  : code														 |
+-------------------------------------------------------------------+


   MODULE  : MFW_BT_DB

   PURPOSE : This module contains the functions for MFW Bluetooth Data Base facilities. It is a LOCAL
   			DATA BASE, thus doesn't require the BT stack to be started. Just call the mfw_bt_flash_init( )
   			function to be able to use the following functions.


*/

#define ENTITY_MFW

#include <string.h>

#if defined (NEW_FRAME)

#include "typedefs.h"
#include "vsi.h"
#include "pei.h"
#include "custom.h"
#include "gsm.h"

#else

#include "STDDEFS.H"
#include "custom.h"
#include "gsm.h"
#include "vsi.h"

#endif

#include "mfw_ffs.h"
#include "mfw_bte.h"
#include "mfw_bt_dm.h"
#include "mfw_bt_geh.h"
#include "mfw_bt_flash.h"


/*****************************************************************************
 ** Constants. Please do not modify length of the parameters, because of alignement 
 constraints in flash
 *****************************************************************************/


/* this is the template for the conf file in case it does not exist or is corrupted */
 
static const tMFW_BT_CFG mfw_bt_default_cfg = {
    MFW_BT_ENABLED,
    MFW_BT_DISCOVERABLE_MODE,
    NULL
};

/* Also keep an image of the flash file in RAM */
static tMFW_BT_CFG mfw_bt_current_cfg;

/* we store the devices data base in a static structure because it will be loaded each time
the phone is powered on: there is no need here to allocate/free memory dynamically . */
static T_MFW_BT_REM_DEVICE mfw_bt_device_db[MFW_BT_NUM_REM_DEVICE];
const UINT8 MFW_BT_FLASH_DB_SIZE = MFW_BT_NUM_REM_DEVICE*sizeof(T_MFW_BT_REM_DEVICE);

/* newly found devices => RAM database */
static T_MFW_BT_REM_DEVICE 	mfw_bt_inq_db[MFW_BT_NUM_REM_DEVICE];


/*
* Local functions
*/

/* update the device data base in flash */
static int mfw_bt_flash_store_db(void);
/* load the device data base in RAM */
static int mfw_bt_flash_read_db(void);
/* store config file in flash */
static int mfw_bt_flash_store_cfg( void );
/* load config file in RAM */
static int mfw_bt_flash_read_cfg( void );



/*******************************************************************************

 $Function:		mfw_bt_flash_init

 $Description:		update the RAM information with the files in flash

 $Returns:		TRUE if OK, wrong is something failed => no stored file, and not possible to 
 				create a new one. Typically, this mean the flash is not formatted.

 $Arguments:		None

*******************************************************************************/
BOOL mfw_bt_flash_init( void )
{
	int status_db, status_cfg;
	/* first, read config file */
	status_cfg = mfw_bt_flash_read_cfg( );
	/* then load the saved device data base in RAM */
	status_db = mfw_bt_flash_read_db( );
	if( status_cfg < 0 || status_db < 0 )
		/* something wrong happened, notify it */
		return FALSE;

	return TRUE;
}




/*******************************************************************************

 $Function:		mfw_bt_read_status

 $Description:		update the flash information with the files in flash

 $Returns:		TRUE if OK, wrong is something failed => no stored file, and not possible to 
 				create a new one. Typically, this mean the flash is not formatted

 $Arguments:		UINT32, value of bt_enable flag. 1 if enabled.

*******************************************************************************/
BOOL mfw_bt_read_status( void )
{
	return mfw_bt_current_cfg.bt_enable;
}



/*******************************************************************************

 $Function:		mfw_bt_store_status

 $Description:		update the BT status in flash

 $Returns:		MFW_BT_SUCCESS if OK, wrong is something failed => no stored file, and not possible to 
 				create a new one. Typically, this mean the flash is not formatted

 $Arguments:		new BT status: TRUE if enabled, FALSE if disabled.

*******************************************************************************/
T_MFW_BT_STATUS mfw_bt_store_status( BOOL new_enable_status )
{
	mfw_bt_current_cfg.bt_enable = new_enable_status;
	if( mfw_bt_flash_store_cfg() != (int)EFFS_OK)
			return MFW_BT_FAIL;

	return MFW_BT_SUCCESS;
}

/*******************************************************************************

 $Function:		mfw_bt_read_visibility

 $Description:		read the discoverability setting

 $Returns:		discoverability setting => TRUE if visible, FALSE if hidden

 $Arguments:		None

*******************************************************************************/
BOOL mfw_bt_read_visibility( void )
{
	return mfw_bt_current_cfg.discoverable;
}

/*******************************************************************************

 $Function:		mfw_bt_store_visibility

 $Description:		store the discoverability setting

 $Returns:		MFW_BT_SUCCESS if OK, MFW_BT_FAIL is something failed 
 				=> no stored file, and not possible to 
 				create a new one. Typically, this mean the flash is not formatted

 $Arguments:		new discoverability setting: TRUE if visible, FALSE if hidden

*******************************************************************************/
T_MFW_BT_STATUS mfw_bt_store_visibility( BOOL new_visibility )
{
	mfw_bt_current_cfg.discoverable = new_visibility;
	if( mfw_bt_flash_store_cfg() != (int)EFFS_OK)
			return MFW_BT_FAIL;

	return MFW_BT_SUCCESS;
}

/*******************************************************************************

 $Function:		mfw_bt_read_local_name

 $Description:		read local BT name

 $Returns:		local BT name. Pointer to a the string in the local database => this has to 
 				be copied if needed for other things.

 $Arguments:		None

*******************************************************************************/
UINT8* mfw_bt_read_local_name( void )
{
	return (UINT8*) mfw_bt_current_cfg.local_device_name;
}

/*******************************************************************************

 $Function:		mfw_bt_store_local_name

 $Description:		update the local name in flash

 $Returns:		MFW_BT_SUCCESS if OK, MFW_BT_FAIL is something failed 
 				=> typically, this mean the flash is not formatted

 $Arguments:		new local name. This data is copied and not freed.

*******************************************************************************/
T_MFW_BT_STATUS mfw_bt_store_local_name( char* new_name )
{
	if( new_name == NULL )
		return MFW_BT_FAIL;
	mfwStrncpy(mfw_bt_current_cfg.local_device_name, new_name, MFW_BT_NAME_LENGTH);

	if( mfw_bt_flash_store_cfg() != (int)EFFS_OK)
			return MFW_BT_FAIL;

	return MFW_BT_SUCCESS;
}




 
 
/*******************************************************************************

 $Function:		mfw_bt_flash_store_device

 $Description:		stores peer device to NVRAM. If device not already in data base => add it. If
 				there, update its information. !!! It will overwrite existing information! Use
 				this function wisely!=> typically, call mfw_bt_flash_get_device_info before to
 				get the pointer of an existing device, or allocate memory for a new one.

 $Returns:		MFW_BT_DATA_BASE_FULL if data base full. MFW_BT_FAIL if not 
 				able to write in flash. Else, success.

 $Arguments:		pointer to a device descriptor. IF NOT ALREADY IN THE DATABASE, WILL BE
 				COPIED. IF ALREADY IN THE DATABASE, THE DATA IS NOT COPIED!

*******************************************************************************/
T_MFW_BT_STATUS mfw_bt_flash_store_device( T_MFW_BT_REM_DEVICE * p_rem_device)
{
    	UINT8 i;

	/* first verify if we already have the device in our list */
	for(i=0; i<MFW_BT_NUM_REM_DEVICE; i++)
	{
		if( memcmp(&mfw_bt_device_db[i].bd_addr[0], &p_rem_device->bd_addr[0], BD_ADDR_LEN) == 0)
			/* ok, we found our device */		
			break;
	}
	if(i == MFW_BT_NUM_REM_DEVICE)
	{
		/* we are here => our device is not yet known. */
		for(i=0; i<MFW_BT_NUM_REM_DEVICE; i++)
			if(!(mfw_bt_device_db[i].in_use))
				/* we just found an empty record, great. */
				break;
	}
	/* verify if the database is not full */
	if( i == MFW_BT_NUM_REM_DEVICE)
    		return MFW_BT_DATA_BASE_FULL;


	/* 	we are here. This means either we found our device in the DB, either we have an empty
		record to fill in with our new device ( typically into the inquiry data base ). So first verify
		if it's a know device. */
	if( p_rem_device != &mfw_bt_device_db[i])
	{
		/* it's a new record, so copy it in our local db */
		memcpy(&mfw_bt_device_db[i], p_rem_device, sizeof(T_MFW_BT_REM_DEVICE));
	}
	mfw_bt_device_db[i].in_use = TRUE;
	mfw_bt_device_db[i].is_new = FALSE;		



	/* update data base in nvram */
	if( mfw_bt_flash_store_db() != EFFS_OK )
		return MFW_BT_FAIL;
	return MFW_BT_SUCCESS;
}



/*******************************************************************************

 $Function:		mfw_bt_clean_inq_db

 $Description:		clean the contents of the inquiry data base in RAM. To be called before each
 				new inquiry.

 $Returns:		

 $Arguments:		

*******************************************************************************/
void mfw_bt_clean_inq_db( void )
{	
	UINT8 i;
	/*
	** CQ21834 : use the sizeof function to take into account any padding bytes which may have been added
	*/
	memset( (void*)mfw_bt_inq_db, 0,  sizeof(mfw_bt_inq_db));
	for( i=0;i<MFW_BT_NUM_REM_DEVICE; i++ ) 
		mfw_bt_inq_db[i].is_new = TRUE;
}



/*******************************************************************************

 $Function:		mfw_bt_add_inq_device

 $Description:		copy the information received into the RAM inquiry database. 

 $Returns:		T_MFW_BT_STATUS. MFW_BT_DATA_BASE_FULL or SUCCESS.

 $Arguments:		pointer to an inquiry result. Data is copied.

*******************************************************************************/
T_MFW_BT_STATUS mfw_bt_add_inq_device( T_MFW_BT_DM_INQ_RES* p_rem_device)
{
    	UINT8 i;

	/* first verify if we already have the device in our list */
	for(i=0; i<MFW_BT_NUM_REM_DEVICE; i++)
	{
		if(!(mfw_bt_inq_db[i].in_use))
		{
			/* we just found an empty record, great. */
			break;
		}
		else if (memcmp(&mfw_bt_inq_db[i].bd_addr, &p_rem_device->bd_addr, sizeof(BD_ADDR)) == 0)
		{
			/* we already know about this device ... just exit indicating SUCCESS */
			return MFW_BT_SUCCESS;
		}
	}
	
	/* verify if the database is not full */
	if(i == MFW_BT_NUM_REM_DEVICE)
    		return MFW_BT_DATA_BASE_FULL;	

	/* we found an unused device record. Update it */
	mfw_bt_inq_db[i].in_use = TRUE;
	memcpy(mfw_bt_inq_db[i].bd_addr, p_rem_device->bd_addr, BD_ADDR_LEN);
	memcpy(mfw_bt_inq_db[i].dev_class, p_rem_device->dev_class, BD_ADDR_LEN);
	return MFW_BT_SUCCESS;
	
}



/*******************************************************************************

 $Function:		mfw_bt_add_disc_device

 $Description:		copy the information received into the RAM inquiry database.  

 $Returns:		T_MFW_BT_STATUS. MFW_BT_DATA_BASE_FULL or SUCCESS.

 $Arguments:		pointer to a discovery result. Data is copied.

*******************************************************************************/
T_MFW_BT_STATUS mfw_bt_add_disc_device( T_MFW_BT_DM_DISC_RES* p_rem_device)
{
    	UINT8 i;

	/* first verify if we already have the device in our list */
	for(i=0; i<MFW_BT_NUM_REM_DEVICE; i++)
	{
		if( memcmp(&mfw_bt_inq_db[i].bd_addr, &p_rem_device->bd_addr, sizeof(BD_ADDR)) == 0)
		{
				/* we just found an empty record, great. */
				break;
		}
	}

	/* verify if the database is not full */
	if(i == MFW_BT_NUM_REM_DEVICE)
    		return MFW_BT_DATA_BASE_FULL;

	/* now update the device with the new informations */
	mfwStrncpy((char*)mfw_bt_inq_db[i].name, (char*)p_rem_device->name, MFW_BT_NAME_LENGTH);
	/*
	** CQ21834 : Update the Friendly Name also.
	*/
	mfwStrncpy((char*)mfw_bt_inq_db[i].friendly_name, (char*)p_rem_device->name, MFW_BT_NAME_LENGTH);
	mfw_bt_inq_db[i].services = p_rem_device->services;

	return MFW_BT_SUCCESS;

}

/*******************************************************************************

 $Function:		mfw_bt_get_device_info

 $Description:		gets the device record of a stored device.  

 $Returns:		NULL if device not found. Pointer to a device structure if found. This data should
 				be copied if wanted to be used somewhere else.
 				If the device is not stored in Flash, the is_new flag is set => this means it is
 				a newly found device ( from an inquiry or discovery result ).

 $Arguments:		DB_ADDR of the device wanted.
 

*******************************************************************************/
T_MFW_BT_REM_DEVICE * mfw_bt_get_device_info(BD_ADDR bd_addr)
{
	UINT8 i;
	T_MFW_BT_REM_DEVICE *p_device;
	
	for(i=0; i<MFW_BT_NUM_REM_DEVICE; i++)
	{
		if (mfw_bt_device_db[i].in_use)
		{
			if(memcmp(&mfw_bt_device_db[i].bd_addr[0], &bd_addr[0], BD_ADDR_LEN) == 0)
			{
				return &mfw_bt_device_db[i];
			}
		}
	}

	/* we didn't find our device, look into the inquiry db */
	for(i=0; i<MFW_BT_NUM_REM_DEVICE; i++)
	{
		if (mfw_bt_inq_db[i].in_use)
		{
			if(memcmp(&mfw_bt_inq_db[i].bd_addr[0], &bd_addr[0], BD_ADDR_LEN) == 0)
			{
				return &mfw_bt_inq_db[i];
			}
		}
	}

	return NULL;

}


/*******************************************************************************

 $Function:		mfw_bt_get_device_by_service

 $Description:		gets a list of device records corresponding to the given service. If service = 0,
 				will return all the stored devices.

 $Returns:		T_MFW_BT_STATUS

 $Arguments:		services => mask of services to look for
 
 				pp_device: a pointer to a T_MFW_BT_REM_DEVICE[MFW_BT_NUM_REM_DEVICE]
 				array. THIS MEMORY HAVE TO BE ALLOCATED!!! This function will add the 
 				pointers one by one into this array!!! The pointers are pointing on local data =>
 				might need to be copied.
 				(Note ... The pointer pp_device is a pointer to an ARRAY OF POINTERS of type T_MFW_BT_REM_DEVICE,
 				ie declared in the calling function as T_MFW_BT_REM_DEVICE *ptr_device[MFW_BT_NUM_REM_DEVICE])

 				number_of_devices: will be used to return the number of devices matching
 				the service mask.
 				
*******************************************************************************/
void mfw_bt_get_device_by_service( T_MFW_BT_SERVICE_MASK services,
														T_MFW_BT_REM_DEVICE ** pp_device,
														UINT8*	number_of_devices )
{
	UINT8 i;

	*number_of_devices = 0;
	if( services == 0 )
		services = BTA_ALL_SERVICE_MASK;
	
	for(i=0; i<MFW_BT_NUM_REM_DEVICE; i++)
	{
		/*
		** CQ21834 : The entry in the known devices database is valid only if the 'in_use' flag is TRUE AND
		** 			the 'is_new' flag is FALSE.
		*/
		if ( ( mfw_bt_device_db[i].in_use == TRUE ) && (mfw_bt_device_db[i].is_new == FALSE))
		{
			if ( (mfw_bt_device_db[i].services & services) != 0 )
			{
				MFW_BT_TRACE_P1("mfw_bt_get_device_by_service(), Device %d is Active and matches the criteria", i);
				pp_device[(*number_of_devices)] = &mfw_bt_device_db[i];
				(*number_of_devices) ++;
			}
		}
	}
	return;
}



/*******************************************************************************

 $Function:		mfw_bt_flash_delete_device

 $Description:		deletes the device from nvram

 $Returns:		MFW_BT_FAIL, MFW_BT_SUCCESS, 
 				MFW_BT_UNKNOWN_DEVICE

 $Arguments:		BD_ADDR of the device to remove from flash.
 				
*******************************************************************************/
T_MFW_BT_STATUS mfw_bt_flash_delete_device(BD_ADDR bd_addr)
{
    UINT8 i;
	T_MFW_BT_STATUS status;
	T_MFW_BT_REM_DEVICE *p_device;

    for(i=0; i<MFW_BT_NUM_REM_DEVICE; i++)
    {
		if(memcmp(&mfw_bt_device_db[i].bd_addr[0], &bd_addr[0], BD_ADDR_LEN) == 0)
        {
			/*
			** CQ21834 : Erase the details from the Device Database and check whether the
			** device is in the Inquiry Database. If so, set the 'is_new' flag in the Inquiry Db
			** to TRUE to indicate that the device is 'not known'
			*/
			memset(&mfw_bt_device_db[i], 0x00, sizeof(T_MFW_BT_REM_DEVICE));

			status = mfw_bt_flash_store_device(&mfw_bt_device_db[i]);

			p_device = mfw_bt_get_device_info(bd_addr);

			if (p_device != NULL)
			{
				p_device->is_new = TRUE;
			}

			return status;

		}
	}

	return MFW_BT_UNKNOWN_DEVICE;
}




/*******************************************************************************

 $Function:		mfw_bt_flash_store_db

 $Description:		write the whole device data base in flash

 $Returns:		=0 if ok, <0 if error ( see ffs code )

 $Arguments:		none

*******************************************************************************/
static int mfw_bt_flash_store_db(void)
{ 
	effs_t    status;

	/*
	** CQ21834 : use the sizeof function to take into account any padding bytes which may have been added
	*/
	status = flash_data_write( MFW_BT_CFG_ROOT_PATH,
							MFW_BT_SEC_FILE,
							(void *)&mfw_bt_device_db,
							sizeof(mfw_bt_device_db));
	if ( status != EFFS_OK )
	{
	    /* mmh thats bad, well go with stored default config. */
	    MFW_BT_TRACE_P1(" mfw_bt_nv_init_device_db(): flash_data_write failed: %d", status );
	}

	return (int)status;
}



/*******************************************************************************

 $Function:		mfw_bt_flash_read_cfg

 $Description:		load the BT config from flash to RAM

 $Returns:		>0 if read ok, =0 if create default ok, <0 if error ( see ffs code )

 $Arguments:		none

*******************************************************************************/
static int mfw_bt_flash_read_cfg( void )
{
	int 	status;
	effs_t ffs_status;

	/* first, reset RAM-based config */
	memset(&mfw_bt_current_cfg,0x00,sizeof(mfw_bt_current_cfg));

	/* then read the one in flash */
	status = flash_data_read ( MFW_BT_CFG_ROOT_PATH,
							 MFW_BT_CFG_FILE, 
							 (void *)&mfw_bt_current_cfg, 
							 sizeof(tMFW_BT_CFG) );
	if( status <= 0)
	{
		/* no config file? => update the RAM settings with the default ones */
		mfw_bt_current_cfg.bt_enable = MFW_BT_ENABLED;
		mfw_bt_current_cfg.discoverable = MFW_BT_DISCOVERABLE_MODE;
		memset(&mfw_bt_current_cfg.local_device_name, 0x00, MFW_BT_NAME_LENGTH);

		/* then try to create one */
		MFW_BT_TRACE(" mfw_bt_read_cfg_file(): flash_data_read failed. Create default one.");
		ffs_status = flash_data_write(MFW_BT_CFG_ROOT_PATH,
								     MFW_BT_CFG_FILE,
		                                		     (void *)&mfw_bt_current_cfg,
		                                		     sizeof(tMFW_BT_CFG));
		if ( ffs_status != EFFS_OK )
		{
			/* mmh thats really bad! */
			MFW_BT_TRACE_P1(" mfw_bt_read_cfg_file(): flash_data_write failed: %d", ffs_status );
			status = (int)ffs_status;
		}
		else
			status = sizeof(tMFW_BT_CFG);
	}

	/* else, nothing to do: mfw_bt_current_cfg has already been updated */
	return status;
}
	



/*******************************************************************************

 $Function:		mfw_bt_flash_store_cfg

 $Description:		writes the cfg file in flash

 $Returns:		=0 if ok, <0 if error ( see ffs code )

 $Arguments:		none

*******************************************************************************/
static int mfw_bt_flash_store_cfg( void )
{
	effs_t 	status;

	status = flash_data_write(MFW_BT_CFG_ROOT_PATH,
							MFW_BT_CFG_FILE,
							(void *)&mfw_bt_current_cfg,
	                                		sizeof(mfw_bt_current_cfg));
	if ( status != EFFS_OK )
	{
		/* mmh thats really bad! */
		MFW_BT_TRACE_P1(" mfw_bt_store_cfg_file(): flash_data_write failed: %d", status );
	}

	/* else, nothing to do, just return */
	return (int)status;
}



/*******************************************************************************

 $Function:		mfw_bt_flash_read_db

 $Description:		load the device data base from flash to RAM

 $Returns:		>0 if read ok, =0 if create default ok, <0 if error ( see ffs code )

 $Arguments:		none

*******************************************************************************/
static int mfw_bt_flash_read_db(void)
{
	int status;
	effs_t ffs_status;

	/* Phone needs to store in nvram some information about other bluetooth devices 
	which it regularly communicates with. The information that has to be stored typically 
	are bdaddr, name, link_key, trust relationship etc.  */	
	MFW_BT_TRACE( "mfw_bt_flash_read_db()");
	
	/* first, reset RAM-based db */
	memset(&mfw_bt_device_db,0x00,sizeof(mfw_bt_device_db));

	/* try to read existing device database stored in nv-ram */
	status = flash_data_read( MFW_BT_CFG_ROOT_PATH,
							MFW_BT_SEC_FILE,
	                             		(void *)&mfw_bt_device_db,
	                             		sizeof(mfw_bt_device_db));

	if ( status <= 0 )
	{
		/* failed => the device db file doesn't exist. Create an empty one. */
		MFW_BT_TRACE(" mfw_bt_flash_read_db(): flash_data_read failed. Create one" );

		ffs_status = flash_data_write( MFW_BT_CFG_ROOT_PATH,
									MFW_BT_SEC_FILE,
									(void *)&mfw_bt_device_db,
									sizeof(mfw_bt_device_db));

		if ( ffs_status != EFFS_OK )
		{
		    /* mmh thats really bad, well go with stored default config. */
		    MFW_BT_TRACE_P1(" mfw_bt_flash_read_db(): flash_data_write failed: %d", ffs_status );
			status = (int)ffs_status;
		}
		else
			status = sizeof(tMFW_BT_CFG);
	}
	return status;
}







