text: /********************************************************************************************************
   * @file	app.c
   *
   * @brief	This is the source file for BLE SDK
   *
   * @author	BLE GROUP
   * @date	2020.06
   *
   * @par     Copyright (c) 2020, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
   *
   *          Licensed under the Apache License, Version 2.0 (the "License");
   *          you may not use this file except in compliance with the License.
   *          You may obtain a copy of the License at
   *
   *              http://www.apache.org/licenses/LICENSE-2.0
   *
   *          Unless required by applicable law or agreed to in writing, software
   *          distributed under the License is distributed on an "AS IS" BASIS,
   *          WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *          See the License for the specific language governing permissions and
   *          limitations under the License.
   *******************************************************************************************************/
  #include "tl_common.h"
  #include "drivers.h"
  #include "stack/ble/ble.h"
  
  #include "app.h"
  #include "app_buffer.h"
  #include "app_att.h"
  #include "app_ui.h"
  #include "application/keyboard/keyboard.h"
  
  
  
  _attribute_ble_data_retention_	int	master_smp_pending = 0; 		// SMP: security & encryption;
  _attribute_ble_data_retention_	u8 ota_is_working = 0;
  
  
  
  const u8	tbl_advData[] = {
  	 11, DT_COMPLETE_LOCAL_NAME, 				's','l','a','v','e','_', 'd','e','m','o',
  	 2,	 DT_FLAGS, 								0x05, 					// BLE limited discoverable mode and BR/EDR not supported
  	 3,  DT_APPEARANCE, 						0x80, 0x01, 			// 384, Generic Remote Control, Generic category
  	 5,  DT_INCOMPLT_LIST_16BIT_SERVICE_UUID,	0x12, 0x18, 0x0F, 0x18,	// incomplete list of service class UUIDs (0x1812, 0x180F)
  };
  
  const u8	tbl_scanRsp [] = {
  	 11, DT_COMPLETE_LOCAL_NAME, 				's','l','a','v','e','_', 'd','e','m','o',
  };
  
  
  
  /**
   * @brief      BLE Connection complete event handler
   * @param[in]  p         Pointer point to event parameter buffer.
   * @return
   */
  _attribute_ble_data_retention_ u8 dbg_req_cnt = 0;
  int app_le_connection_complete_event_handle(u8 *p)
  {
  	hci_le_connectionCompleteEvt_t *pConnEvt = (hci_le_connectionCompleteEvt_t *)p;
  
  	if(pConnEvt->status == BLE_SUCCESS){
  
  		dev_char_info_insert_by_conn_event(pConnEvt);
  
  		if(pConnEvt->role == LL_ROLE_SLAVE){
  			bls_l2cap_requestConnParamUpdate (pConnEvt->connHandle, CONN_INTERVAL_10MS, CONN_INTERVAL_10MS, 99, CONN_TIMEOUT_4S);	// 1 second
  //			bls_l2cap_requestConnParamUpdate (pConnEvt->connHandle, CONN_INTERVAL_10MS, CONN_INTERVAL_10MS, 199, CONN_TIMEOUT_6S);	// 2 second
  //			bls_l2cap_requestConnParamUpdate (pConnEvt->connHandle, CONN_INTERVAL_10MS, CONN_INTERVAL_10MS, 299, CONN_TIMEOUT_8S);	// 3 second
  
  			//test code
  			#if 0
  				dbg_req_cnt ++;
  				if(dbg_req_cnt & 1){
  					bls_l2cap_requestConnParamUpdate (pConnEvt->connHandle, CONN_INTERVAL_10MS, CONN_INTERVAL_10MS, 4, CONN_TIMEOUT_4S);
  				}
  				else{
  					bls_l2cap_requestConnParamUpdate (pConnEvt->connHandle, CONN_INTERVAL_10MS, CONN_INTERVAL_10MS, 5, CONN_TIMEOUT_4S);
  				}
  			#elif 0
  
  				if(dbg_req_cnt == 0){
  					bls_l2cap_requestConnParamUpdate (pConnEvt->connHandle, CONN_INTERVAL_10MS, CONN_INTERVAL_10MS, 99, CONN_TIMEOUT_4S);
  				}
  				else if(dbg_req_cnt == 1){
  					bls_l2cap_requestConnParamUpdate (pConnEvt->connHandle, CONN_INTERVAL_10MS, CONN_INTERVAL_10MS, 199, CONN_TIMEOUT_6S);
  				}
  				else{
  					bls_l2cap_requestConnParamUpdate (pConnEvt->connHandle, CONN_INTERVAL_10MS, CONN_INTERVAL_10MS, 299, CONN_TIMEOUT_8S);
  				}
  
  				dbg_req_cnt ++;
  				if(dbg_req_cnt > 2){
  					dbg_req_cnt = 0;
  				}
  			#endif
  		}
  	}
  
  	return 0;
  }
  
  
  
  /**
   * @brief      BLE Disconnection event handler
   * @param[in]  p         Pointer point to event parameter buffer.
   * @return
   */
  int 	app_disconnect_event_handle(u8 *p)
  {
  	event_disconnection_t	*pCon = (event_disconnection_t *)p;
  
  	//terminate reason
  	if(pCon->reason == HCI_ERR_CONN_TIMEOUT){  	//connection timeout
  
  	}
  	else if(pCon->reason == HCI_ERR_REMOTE_USER_TERM_CONN){  	//peer device send terminate command on link layer
  
  	}
  	//master host disconnect( blm_ll_disconnect(current_connHandle, HCI_ERR_REMOTE_USER_TERM_CONN) )
  	else if(pCon->reason == HCI_ERR_CONN_TERM_BY_LOCAL_HOST){
  
  	}
  	else{
  
  	}
  
  
  
  	dev_char_info_delete_by_connhandle(pCon->connHandle);
  
  
  	return 0;
  }
  
  
  /**
   * @brief      BLE Connection update complete event handler
   * @param[in]  p         Pointer point to event parameter buffer.
   * @return
   */
  int app_le_connection_update_complete_event_handle(u8 *p)
  {
  	hci_le_connectionUpdateCompleteEvt_t *pUpt = (hci_le_connectionUpdateCompleteEvt_t *)p;
  
  	if(pUpt->status == BLE_SUCCESS){
  
  	}
  
  	return 0;
  }
  
  //////////////////////////////////////////////////////////
  // event call back
  //////////////////////////////////////////////////////////
  /**
   * @brief      BLE controller event handler call-back.
   * @param[in]  h       event type
   * @param[in]  p       Pointer point to event parameter buffer.
   * @param[in]  n       the length of event parameter.
   * @return
   */
  int app_controller_event_callback (u32 h, u8 *p, int n)
  {
  	if (h &HCI_FLAG_EVENT_BT_STD)		//Controller HCI event
  	{
  		u8 evtCode = h & 0xff;
  
  		//------------ disconnect -------------------------------------
  		if(evtCode == HCI_EVT_DISCONNECTION_COMPLETE)  //connection terminate
  		{
  			app_disconnect_event_handle(p);
  		}
  		else if(evtCode == HCI_EVT_LE_META)  //LE Event
  		{
  			u8 subEvt_code = p[0];
  
  			//------hci le event: le connection complete event---------------------------------
  			if (subEvt_code == HCI_SUB_EVT_LE_CONNECTION_COMPLETE)	// connection complete
  			{
  				app_le_connection_complete_event_handle(p);
  			}
  			//--------hci le event: le adv report event ----------------------------------------
  			else if (subEvt_code == HCI_SUB_EVT_LE_ADVERTISING_REPORT)	// ADV packet
  			{
  
  			}
  			//------hci le event: le connection update complete event-------------------------------
  			else if (subEvt_code == HCI_SUB_EVT_LE_CONNECTION_UPDATE_COMPLETE)	// connection update
  			{
  				app_le_connection_update_complete_event_handle(p);
  			}
  		}
  	}
  
  
  	return 0;
  
  }
  
  
  
  
  /**
   * @brief      BLE host event handler call-back.
   * @param[in]  h       event type
   * @param[in]  para    Pointer point to event parameter buffer.
   * @param[in]  n       the length of event parameter.
   * @return
   */
  int app_host_event_callback (u32 h, u8 *para, int n)
  {
  	u8 event = h & 0xFF;
  
  	switch(event)
  	{
  		case GAP_EVT_SMP_PAIRING_BEGIN:
  		{
  
  		}
  		break;
  
  		case GAP_EVT_SMP_PAIRING_SUCCESS:
  		{
  
  		}
  		break;
  
  		case GAP_EVT_SMP_PAIRING_FAIL:
  		{
  
  		}
  		break;
  
  		case GAP_EVT_SMP_CONN_ENCRYPTION_DONE:
  		{
  
  		}
  		break;
  
  		case GAP_EVT_SMP_SECURITY_PROCESS_DONE:
  		{
  
  		}
  		break;
  
  		case GAP_EVT_SMP_TK_DISPALY:
  		{
  
  		}
  		break;
  
  		case GAP_EVT_SMP_TK_REQUEST_PASSKEY:
  		{
  
  		}
  		break;
  
  		case GAP_EVT_SMP_TK_REQUEST_OOB:
  		{
  
  		}
  		break;
  
  		case GAP_EVT_SMP_TK_NUMERIC_COMPARE:
  		{
  
  		}
  		break;
  
  		case GAP_EVT_ATT_EXCHANGE_MTU:
  		{
  
  		}
  		break;
  
  		case GAP_EVT_GATT_HANDLE_VLAUE_CONFIRM:
  		{
  
  		}
  		break;
  
  		default:
  		break;
  	}
  
  	return 0;
  }
  
  
  /**
   * @brief      BLE GATT data handler call-back.
   * @param[in]  connHandle     connection handle.
   * @param[in]  pkt             Pointer point to data packet buffer.
   * @return
   */
  int app_gatt_data_handler (u16 connHandle, u8 *pkt)
  {
  
  	if( dev_char_get_conn_role_by_connhandle(connHandle) == LL_ROLE_MASTER )   //GATT data for Master
  	{
  			//so any ATT data before service discovery will be dropped
  			dev_char_info_t* dev_info = dev_char_info_search_by_connhandle (connHandle);
  			if(dev_info)
  			{
  				//-------	user process ------------------------------------------------
  				rf_packet_att_t *pAtt = (rf_packet_att_t*)pkt;
  				//u16 attHandle = pAtt->handle;
  
  				if(pAtt->opcode == ATT_OP_HANDLE_VALUE_NOTI)  //slave handle notify
  				{
  
  				}
  				else if (pAtt->opcode == ATT_OP_HANDLE_VALUE_IND)
  				{
  
  				}
  			}
  
  	}
  	else{   //GATT data for Slave
  
  
  	}
  
  
  	return 0;
  }
  
  
  
  
  
  
  
  
  
  
  /**
   * @brief      callBack function of LinkLayer Event "BLT_EV_FLAG_SUSPEND_EXIT"
   * @param[in]  e - LinkLayer Event type
   * @param[in]  p - data pointer of event
   * @param[in]  n - data length of event
   * @return     none
   */
  _attribute_ram_code_ void	user_set_rf_power (u8 e, u8 *p, int n)
  {
  	rf_set_power_level_index (RF_POWER_P0dBm);
  }
  
  
  
  /**
   * @brief		user initialization when MCU power on or wake_up from deepSleep mode
   * @param[in]	none
   * @return      none
   */
  _attribute_no_inline_ void user_init_normal(void)
  {
  	/* random number generator must be initiated here( in the beginning of user_init_nromal).
  	 * When deepSleep retention wakeUp, no need initialize again */
  	random_generator_init();
  
  //////////////////////////// BLE stack Initialization  Begin //////////////////////////////////
  
  	u8  mac_public[6];
  	u8  mac_random_static[6];
  	blc_initMacAddress(flash_sector_mac_address, mac_public, mac_random_static);
  
  
  	//////////// LinkLayer Initialization  Begin /////////////////////////
  	blc_ll_initBasicMCU();
  
  	blc_ll_initStandby_module(mac_public);						   //mandatory
  
      blc_ll_initLegacyAdvertising_module(); 	//adv module: 		 mandatory for BLE slave,
  
  	blc_ll_initAclConnection_module();
  
  	blc_ll_initAclSlaveRole_module();
  
  	blc_ll_setMaxConnectionNumber( MASTER_MAX_NUM, 1); //SLAVE_MAX_NUM
  
  	blc_ll_setAclConnMaxOctetsNumber(ACL_CONN_MAX_RX_OCTETS, ACL_MASTER_MAX_TX_OCTETS, ACL_SLAVE_MAX_TX_OCTETS);
  
  	/* all ACL connection share same RX FIFO */
  	blc_ll_initAclConnRxFifo(app_acl_rxfifo, ACL_RX_FIFO_SIZE, ACL_RX_FIFO_NUM);
  
  	/* ACL Slave TX FIFO */
  	blc_ll_initAclConnSlaveTxFifo(app_acl_slvTxfifo, ACL_SLAVE_TX_FIFO_SIZE, ACL_SLAVE_TX_FIFO_NUM, SLAVE_MAX_NUM);
  	//////////// LinkLayer Initialization  End /////////////////////////
  
  
  
  	//////////// HCI Initialization  Begin /////////////////////////
  	blc_hci_registerControllerDataHandler (blc_l2cap_pktHandler);
  
  	blc_hci_registerControllerEventHandler(app_controller_event_callback); //controller hci event to host all processed in this func
  
  	//bluetooth event
  	blc_hci_setEventMask_cmd (HCI_EVT_MASK_DISCONNECTION_COMPLETE);
  
  	//bluetooth low energy(LE) event
  	blc_hci_le_setEventMask_cmd(		HCI_LE_EVT_MASK_CONNECTION_COMPLETE  \
  									|	HCI_LE_EVT_MASK_ADVERTISING_REPORT \
  									|   HCI_LE_EVT_MASK_CONNECTION_UPDATE_COMPLETE);
  
  
  	u8 check_status = blc_controller_check_appBufferInitialization();
  	if(check_status != BLE_SUCCESS){
  		/* here user should set some log to know which application buffer incorrect*/
  		write_log32(0x88880000 | check_status);
  		while(1);
  	}
  	//////////// HCI Initialization  End /////////////////////////
  
  
  	//////////// Host Initialization  Begin /////////////////////////
  	/* Host Initialization */
  	/* GAP initialization must be done before any other host feature initialization !!! */
  	blc_gap_init();
  
  	/* L2CAP buffer Initialization */
  	blc_l2cap_initAclConnSlaveMtuBuffer(mtu_s_rx_fifo, MTU_S_BUFF_SIZE_MAX, mtu_s_tx_fifo, MTU_S_BUFF_SIZE_MAX);
  
  	/* GATT Initialization */
  	my_gatt_init();
  
  	blc_gatt_register_data_handler(app_gatt_data_handler);
  
  	/* SMP Initialization */
  	#if (BLE_SLAVE_SMP_ENABLE || BLE_MASTER_SMP_ENABLE)
  		blc_smp_configPairingSecurityInfoStorageAddressAndSize(FLASH_ADR_SMP_PAIRING, FLASH_SMP_PAIRING_MAX_SIZE);
  	#endif
  
  	#if (BLE_SLAVE_SMP_ENABLE)  //Slave SMP Enable
  		blc_smp_setSecurityLevel_slave(Unauthenticated_Pairing_with_Encryption);  //LE_Security_Mode_1_Level_2
  	#else
  		blc_smp_setSecurityLevel_slave(No_Security);
  	#endif
  
  	blc_smp_smpParamInit();
  
  
  	//host(GAP/SMP/GATT/ATT) event process: register host event callback and set event mask
  	blc_gap_registerHostEventHandler( app_host_event_callback );
  	blc_gap_setEventMask( GAP_EVT_MASK_SMP_PAIRING_BEGIN 			|  \
  						  GAP_EVT_MASK_SMP_PAIRING_SUCCESS   		|  \
  						  GAP_EVT_MASK_SMP_PAIRING_FAIL				|  \
  						  GAP_EVT_MASK_SMP_SECURITY_PROCESS_DONE);
  	//////////// Host Initialization  End /////////////////////////
  
  //////////////////////////// BLE stack Initialization  End //////////////////////////////////
  
  
  
  
  //////////////////////////// User Configuration for BLE application ////////////////////////////
  	blc_ll_setAdvData( (u8 *)tbl_advData, sizeof(tbl_advData) );
  	blc_ll_setScanRspData( (u8 *)tbl_scanRsp, sizeof(tbl_scanRsp));
  	blc_ll_setAdvParam(ADV_INTERVAL_200MS, ADV_INTERVAL_200MS, ADV_TYPE_CONNECTABLE_UNDIRECTED, OWN_ADDRESS_PUBLIC, 0, NULL, BLT_ENABLE_ADV_ALL, ADV_FP_NONE);
  	blc_ll_setAdvEnable(BLC_ADV_ENABLE);  //ADV enable
  	//blc_ll_setMaxAdvDelay_for_AdvEvent(MAX_DELAY_0MS);
  
  	user_set_rf_power(0, 0, 0);
  
  
  	#if (BLE_APP_PM_ENABLE)
  		blc_ll_initPowerManagement_module();
  		blc_pm_setSleepMask(PM_SLEEP_LEG_ADV | PM_SLEEP_ACL_SLAVE);
  
  		#if (PM_DEEPSLEEP_RETENTION_ENABLE)
  			blc_pm_setDeepsleepRetentionEnable(PM_DeepRetn_Enable);
  			blc_pm_setDeepsleepRetentionThreshold(95);
  			blc_pm_setDeepsleepRetentionEarlyWakeupTiming(300);
  		#else
  			blc_pm_setDeepsleepRetentionEnable(PM_DeepRetn_Disable);
  		#endif
  
  		blc_ll_registerTelinkControllerEventCallback (BLT_EV_FLAG_SUSPEND_EXIT, &user_set_rf_power);
  	#endif
  
  	#if (UI_KEYBOARD_ENABLE)
  		keyboard_init();
  	#endif
  
  
  	#if (BLE_OTA_SERVER_ENABLE)
  		/* OTA module initialization must be called after "blc_ota_setFirmwareSizeAndBootAddress"(if used), and before any other OTA API.*/
  		blc_ota_initOtaServer_module();
  		blc_ota_setOtaProcessTimeout(30);
  	#endif
  
  	#if (UART_LOW_POWER_DEBUG_EN)
  		low_power_uart_debug_init();
  	#endif
  ////////////////////////////////////////////////////////////////////////////////////////////////
  
  }
  
  
  
  /**
   * @brief		user initialization when MCU wake_up from deepSleep_retention mode
   * @param[in]	none
   * @return      none
   */
  _attribute_ram_code_ void user_init_deepRetn(void)
  {
  
  #if (PM_DEEPSLEEP_RETENTION_ENABLE)
  
  	blc_ll_initBasicMCU();   //mandatory
  
  	user_set_rf_power(0, 0, 0);
  
  	blc_ll_recoverDeepRetention();
  
  	DBG_CHN0_HIGH;    //debug
  	irq_enable();
  
  	#if (UART_LOW_POWER_DEBUG_EN)
  		low_power_uart_debug_init();
  	#endif
  
  	#if (UI_KEYBOARD_ENABLE)
  		/////////// keyboard GPIO wakeup init ////////
  		u32 pin[] = KB_DRIVE_PINS;
  		for (int i=0; i<(sizeof (pin)/sizeof(*pin)); i++){
  			pm_set_gpio_wakeup (pin[i], WAKEUP_LEVEL_HIGH, 1);  //drive pin pad high level wakeup deepsleep
  		}
  	#endif
  #endif
  }
  
  
  
  
  void app_process_power_management(void)
  {
  #if (BLE_APP_PM_ENABLE)
  
  	blc_pm_setSleepMask(PM_SLEEP_LEG_ADV | PM_SLEEP_ACL_SLAVE );
  
  	int user_task_flg = ota_is_working;
  	#if UI_KEYBOARD_ENABLE
  		user_task_flg = user_task_flg || scan_pin_need || key_not_released;
  	#endif
  
  	if(user_task_flg){
  		blc_pm_setSleepMask(PM_SLEEP_DISABLE);
  	}
  #endif
  }
  
  
  /////////////////////////////////////////////////////////////////////
  // main loop flow
  /////////////////////////////////////////////////////////////////////
  
  /**
   * @brief     BLE main idle loop
   * @param[in]  none.
   * @return     none.
   */
  int main_idle_loop (void)
  {
  
  	////////////////////////////////////// BLE entry /////////////////////////////////
  	blc_sdk_main_loop();
  
  
  	////////////////////////////////////// UI entry /////////////////////////////////
  	#if (UI_KEYBOARD_ENABLE)
  		proc_keyboard (0,0, 0);
  	#endif
  
  	////////////////////////////////////// PM entry /////////////////////////////////
  	app_process_power_management();
  
  	return 0; //must return 0 due to SDP flow
  }
  
  
  
  /**
   * @brief     BLE main loop
   * @param[in]  none.
   * @return     none.
   */
  _attribute_no_inline_ void main_loop (void)
  {
  	main_idle_loop ();
  }
  
  
  
  
  
  