/*
 * Copyright 2016, Yichip Semiconductor(shenzhen office)
 * All Rights Reserved.
 *
 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Yichip Semiconductor;
 * the contents of this file may not be disclosed to third parties, copied
 * or duplicated in any form, in whole or in part, without the prior
 * written permission of Yichip Semiconductor.
 */

/** @file 
 *
 * BT Application for c51 devices
 *
 */
 
#include "yc11xx_bt_interface.h"
#include "ipc.h"
#include "system.h"

#ifndef ATT_LIST_LEN
#define	ATT_LIST_LEN    mem_rc_att_list_end-mem_rc_att_list
#endif


/**************************  SPP FUNCTION ********************************/
/*
 * @method Bt_SndCmdSppStartDiscovery
 * @brief  Open BT3.0 Discovery
 * @retval None
 */
void Bt_SndCmdSppStartDiscovery(void)
{
	IPC_TxControlCmd(IPC_CMD_START_DISCOVERY);
}

/*
 * @method Bt_SndCmdSppStopDiscovery
 * @brief  Close BT3.0 Discovery
 * @retval None
 */
void Bt_SndCmdSppStopDiscovery(void)
{
    IPC_TxControlCmd(IPC_CMD_STOP_DISCOVERY);
}

/*
 * @method Bt_GetSppMac
 * @brief  Get BT3.0 MAC addr
 * @param  adr:pointer to a buf that contains  BT3.0 addr you want read.
 * @retval None
 */
void Bt_GetSppMac(uint8_t *adr)
{
	for(int i = 0;i < 6; i++)
	{
		adr[i] = HREAD((mem_lap+5-i));
	}
}

/*
 * @method Bt_SetSppAddr
 * @brief  Set BT3.0 MAC addr
 * @param  adr:pointer to a buf that contains  BT3.0 addr you want set.
 * @retval None
 */
void Bt_SetSppAddr(uint8_t *adr)
{
	for(int i=0; i<6; i++){
		HWRITE(mem_lap+i,adr[i]);
	}
}

/*
 * @method Bt_SetSppName.
 * @brief  Set BT3.0 Name.
 * @param  name:pointer to a buf that contains  BT3.0 name you want set.
 * @param  len:the buf length.
 * @retval true: Set Success.
 * 		   false :Set fail.
 */
bool Bt_SetSppName(uint8_t *name,int len)
{
	if(len>27)
		return false;
	for(int i=0;i<len;i++)
	{
		HWRITE(mem_local_name_length+1+i,*(name+i));
	}	
    return true;
}

/*
 * @method Bt_SndSppData.
 * @brief  Send BT3.0 data.
 * @param  data:pointer to a buf that contains the data you want send.
 * @param  len:the data length.
 * @retval true: send Success.
 * 		   false :send fail.
 */
bool Bt_SndSppData(uint8_t *data,uint8_t len)
{
	if (len>120) return false;
	IPC_TxCommon(IPC_TYPE_SPP,data,len);
    return true;
}




/**************************  BLE FUNCTION  ********************************/
/*
 * @method Bt_SndCmdLeStartAdv
 * @brief  Open BLE adv_ind adv.
 * @retval None
 */
void Bt_SndCmdLeStartAdv(void)
{
    IPC_TxControlCmd(IPC_CMD_START_ADV);
}

/*
 * @method Bt_SndCmdLeStopAdv
 * @brief  Close BLE adv_ind adv.
 * @retval None
 */
void Bt_SndCmdLeStopAdv(void)
{
    IPC_TxControlCmd(IPC_CMD_STOP_ADV);
}

/*
 * @method Bt_SndCmdLeStartDirectAdv
 * @brief  Open BLE adv_direct_ind
 * @retval None
 */
void Bt_SndCmdLeStartDirectAdv(void)
{
    IPC_TxControlCmd(IPC_CMD_START_DIRECT_ADV);
}

/*
 * @method Bt_SndCmdLeStopDirectAdv
 * @brief  Close BLE adv_direct_ind.
 * @retval None
 */
void Bt_SndCmdLeStopDirectAdv(void)
{
    IPC_TxControlCmd(IPC_CMD_STOP_DIRECT_ADV);
}

/*
 * @method Bt_SndCmdLeStartScanAdv
 * @brief  Close BLE adv_scan_ind.
 * @retval None
 */
void Bt_SndCmdLeStartScanAdv(void)
{
    IPC_TxControlCmd(IPC_CMD_START_SCAN_ADV);   
}

/*
 * @method Bt_SndCmdLeDisconnect
 * @brief  The device actively disconnects Bluetooth.
 * @retval None
 */
void Bt_SndCmdLeDisconnect(void)
{
    IPC_TxControlCmd(IPC_CMD_LE_DISCONNECT);   
}

/*
 * @method Bt_SndCmdLeUpdateConn
 * @brief  Update BLE connection param.
 * @param  param: pointer to a buf that contains the connection param you want send. 
 * @retval None
 */
void Bt_SndCmdLeUpdateConn(BLE_Conn_param* param)
{
	HWRITEW(mem_le_connection_updata_param,param->min_interval);
	HWRITEW(mem_le_connection_updata_param+2,param->max_interval);
	HWRITEW(mem_le_connection_updata_param+4,param->latency);
	HWRITEW(mem_le_connection_updata_param+6,param->timeout);	
    IPC_TxControlCmd(IPC_CMD_UPDATE_CONN);
}

/*
 * @method Bt_SetLocalMtuSize
* @brief  Set  mtu value, range: 23-200.
 * @retval None
 */
void Bt_SetLocalMtuSize(uint16_t size)
{
	if(size>MAX_MTU_SIZE)
		HWRITEW(mem_local_mtu_size,MAX_MTU_SIZE);
	else if(size>MIN_MTU_SIZE)
		HWRITEW(mem_local_mtu_size,size);
	else
		HWRITEW(mem_local_mtu_size,MIN_MTU_SIZE);
}


/*
 * @method Bt_SndCmdLeUpdateAttMTU
 * @brief  Update BLE ATT MTU.
 * @retval None
 */
void Bt_SndCmdLeUpdateAttMTU(void)
{
    IPC_TxControlCmd(IPC_CMD_MTU_EXCHANGE);  
}

/*
 * @method Bt_GetLeMac
 * @brief  Get BLE MAC addr
 * @param  adr:pointer to a buf that contains  the current BLE mac addr you want read.
 * @retval None
 */
void Bt_GetLeMac(uint8_t *adr)
{
	for(int i = 0;i < 6; i++)
	{
		adr[i] = HREAD((mem_le_lap+5-i));
	}
}

/*
 * @method Bt_SetLeMac
 * @brief  Set BLE MAC addr
 * @param  adr:pointer to a buf that contains  BLE addr you want set.
 * @retval None
 */
void Bt_SetLeMac(uint8_t *adr)
{
	for(int i=0; i<6; i++){
		HWRITE(mem_le_lap+i,adr[i]);
	}   
}

/*
 * @method Bt_Re_LeAdvName.
 * @brief  Set BLE adv name.
 * @param  name:pointer to a buf that contains  BLE name you want set.
 * @param  len:the name length.
 * @retval None
 */
uint8_t Bt_Re_LeAdvName(uint8_t *name,uint8_t len)
{
	int length = 0;
	int ad_type,len0,j;
	uint8_t buf[LE_ADV_DATA_MAX_LENGTH];
	len0=HREAD(mem_le_adv_data_len);
	for(int i =0;i<len0;i+=length+1)
	{
		length = HREAD(mem_le_adv_data+i);
		ad_type=HREAD(mem_le_adv_data+i+1);
		if(ad_type==0x09)
		{	
			if((len0-length+len+1)>LE_ADV_DATA_MAX_LENGTH)
				return ERROR;
			for( j=0;j<(len0-i-length-1);j++)
			{
				buf[j] = HREAD(mem_le_adv_data+i+length+1+j);
			}
			for(j=0;j<len;j++)
			{
				HWRITE(mem_le_adv_data+i+2+j,name[j]);
			}
			HWRITE(mem_le_adv_data+i,len+1);
			for(j=0;j<(len0-i-length-1);j++)
			{
				HWRITE(mem_le_adv_data+i+length+1+j,buf[j]);
			}
			HWRITE(mem_le_adv_data_len,len0-length+len+1);
			return SUCCESS;
		}
	}
	return ERROR;
}

/*
 * @method Bt_Re_LeDeivcename.
 * @brief  Set BLE Deivce name.
 * @param  name:pointer to a buf that contains  BLE name you want set.
 * @param  len:the name length.
 * @retval None
 */
void Bt_Re_LeDeivcename(uint8_t *name,uint8_t len)
{
	int i;
	int cache_len,oldname_len;

	uint8_t att_list[ATT_LIST_LEN];
	memset(att_list,0,ATT_LIST_LEN);
	oldname_len=HREAD(mem_rc_att_list+20);
	cache_len =  ATT_LIST_LEN-21-oldname_len;
	#ifdef DEBUG_DRV_BT
	MyPrintf("cache_len=%d\r\n",cache_len);
	#endif
	for(i=0;i<cache_len;i++)
	{
		att_list[i]=HREAD(mem_rc_att_list+21+oldname_len+i);
	}
	#ifdef DEBUG_DRV_BT
	for(i=0;i<20;i++)
	{
		MyPrintf("att_list[%d]=%02x  \r\n",i,att_list[i]);
	}
	#endif
	HWRITE(mem_rc_att_list+20,len);
	for(i=0; i<len; i++){
		HWRITE(mem_rc_att_list+21+i,*(name+i));
	}

	for(i=0;i<cache_len;i++){
		HWRITE(mem_rc_att_list+21+len+i,att_list[i]);
	}
}

/*
 * @method Bt_Renew_Le_AdvData.
 * @brief  Set BLE adv data.
 * @param  data:pointer to a buf that contains  adv data you want set.
 * @param  len:the data length.
 * @retval true: send Success.
 * 		   false :send fail.
 */
bool Bt_Renew_Le_AdvData(uint8_t *data,uint8_t len)
{
	uint8_t length=0;
	if(len > LE_ADV_DATA_MAX_LENGTH)
		return false;
	HWRITE(mem_le_adv_enable,ADV_DISABLE);
	while(len--)
	{
		HWRITE(mem_le_adv_data+length,*data);
		data++;
		length++;
	}
	HWRITE(mem_le_adv_data_len,length);
    return true;
}

/*
 * @method Bt_Renew_Le_ScanRsp.
 * @brief  Set BLE scan_rsp data.
 * @param  data:pointer to a buf that contains  scan_rsp data you want set.
 * @param  len:the data length.
 * @retval true: send Success.
 * 		   false :send fail.
 */
bool Bt_Renew_Le_ScanRsp(uint8_t *data,uint8_t len)
{
	uint8_t length=0;
	if(len > LE_SCAN_RSP_MAX_LENGTH)
		return false;
	HWRITE(mem_le_adv_enable,ADV_DISABLE);
	while(len--)
	{
		HWRITE(mem_le_scan_data+length,*data);
		data++;
		length++;
	}
	HWRITE(mem_le_scan_data_len,length);
    return true;
}

/*
 * @method Bt_SetLeAdvType.
 * @brief  Set BLE adv type.
 * @param  Type:adv Type,it can be one of the following values:
 * 		   ADV_TYPE_NOMAL,ADV_TYPE_DIRECT,ADV_TYPE_NOCONNECT,
 * 		   SCAN_REQ,SCAN_RSP,CONNECT_REQ,ADV_TYPE_SCAN
 * @retval None.
 */
void Bt_SetLeAdvType(advType Type)
{
	HWRITE(mem_le_adv_type, Type);
}

/*
 * @method Bt_SetLeScanRspType.
 * @brief  Set BLE scan type.
 * @param  Type:it can be one of the following values:
 * 		   SCAN_TYPE_PASSIVE,SCAN_TYPE_ACTIVE.
 * @retval None.
 */
void Bt_SetLeScanRspType(scanType Type)
{
	HWRITE(mem_le_scan_type, Type);
}

/*
 * @method Bt_SetLeAdvInterval.
 * @brief  Set BLE adv interval.
 * @param  gap: The interval between adv,unit:0.625ms.
 * @retval None.
 */
void Bt_SetLeAdvInterval(uint16_t gap)
{
	HWRITEW(mem_le_adv_interval_max,gap);
}

/*
 * @method Bt_SndBleData.
 * @brief  Send BLE data.
 * @param  BLE_WRITE_HANDLE:Send the BLE data by the corresponding to the uuid service of this BLE_WRITE_HANDLE. 
 * @param  data:pointer to a buf that contains the data you want send.
 * @param  len:the data length.
 * @retval true: send Success.
 * 		   false :send fail.
 */
bool Bt_SndBleData(uint16_t BLE_WRITE_HANDLE, uint8_t *data, uint8_t len)
{
    uint8_t packet[MAX_MTU_SIZE+2];
    if(len<0 || len> LE_MAX_PATCKET_LENGTH)
  	    return false;
    packet[0]= BLE_WRITE_HANDLE&0xff; 
    packet[1]= (BLE_WRITE_HANDLE>>8)&0xff;  
    memcpy(packet+2,data,len);     
	IPC_TxCommon(IPC_TYPE_BLE,packet,len+2);
    return true;
}

/**************************  SCAN FUNCTION  ********************************/
/*
 * @method Bt_SndCmdStartScan.
 * @brief  Open BLE scan adv data .
 * @retval None.
 */
void Bt_SndCmdStartScan(void)
{
    IPC_TxControlCmd(IPC_CMD_START_SCAN);
}

/*
 * @method Bt_SndCmdStartScan.
 * @brief  Close BLE scan adv data .
 * @retval None.
 */
void Bt_SndCmdStopScan(void)
{
    IPC_TxControlCmd(IPC_CMD_STOP_SCAN);
}


/**************************  HIBERNATE FUNCTION  ********************************/
/*
 * @method Bt_SndCmdPwroff.
 * @brief  Make device to shutdown mode .
 * @retval None.
 */
void Bt_SndCmdPwroff(void)
{
    IPC_TxControlCmd(IPC_CMD_ENTER_HIBERNATE);    
}