/**
 * @file tkl_bluetooth.c
 * @brief this file was auto-generated by tuyaos v&v tools, developer can add implements between BEGIN and END
 * 
 * @warning: changes between user 'BEGIN' and 'END' will be keeped when run tuyaos v&v tools
 *           changes in other place will be overwrited and lost
 *
 * @copyright Copyright 2020-2021 Tuya Inc. All Rights Reserved.
 * 
 */

// --- BEGIN: user defines and implements ---
#include "tkl_bluetooth.h"
#include "tuya_error_code.h"
// --- END: user defines and implements ---
#include "atbm_hal.h"
#include "services/gap/ble_svc_gap.h"
#include "services/dis/ble_svc_dis.h"
#include "services/gatt/ble_svc_gatt.h"

#include "host/ble_gatt.h"
#include "host/ble_att.h"
#include "host/ble_hs.h"
#include "host/ble_gap.h"
#include "host/util/util.h"
#include "nimble/ble_hci_trans.h"
#include "atbm_os_api.h"

static ble_recv_handler recv_handler = NULL;

STATIC TKL_BLE_GAP_EVT_FUNC_CB	g_tlk_ble_gap_event_callback = NULL;

STATIC TKL_BLE_GATT_EVT_FUNC_CB	g_tlk_ble_gatt_event_callback = NULL;

static USHORT_T g_gatt_link;
static TKL_BLE_GAP_ADDR_T g_local_addr;
static TKL_BLE_GAP_ADV_PARAMS_T g_tkl_ble_gatt_adv_param;
static USHORT_T tuya_conn_handle ={0};

static char* g_st_gap_adv_data = NULL;
static int g_st_gap_adv_data_len = 0;
static char* g_st_gap_adv_rsp_data = NULL;
static int g_st_gap_adv_rsp_data_len = 0;

STATIC UCHAR_T adv_data_const[31] =
{
    0x02,
    0x01,
    0x06,
    0x03,
    0x02,
    0x50, 0xFD,
    0x17,
    0x16,
    0x50, 0xFD,
    0x41, 0x00,       //Frame Control
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

STATIC UCHAR_T scan_rsp_data_const[31] =
{   
    0x17,             // length
    0xFF,
    0xD0,
    0x07,
    0x00, //Encry Mode(8)
    0x00,0x00, //communication way bit0-mesh bit1-wifi bit2-zigbee bit3-NB
    0x00, //FLAG
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x03, //24
    0x09,
    0x54, 0x59,
};

static uint8_t ble_status;
static uint16_t ble_conn_handle;

static int ble_gap_event(void *gap_event, void *arg)
{
	struct ble_gap_event *event = (struct ble_gap_event *)gap_event;
	TKL_BLE_GAP_PARAMS_EVT_T gap_evt;
	struct ble_gap_conn_desc desc;
	struct ble_sm_io pkey;
	/* Connection handle */
	//uint16_t conn_handle=1;
	struct ble_gap_upd_params params;
	params.itvl_min=7;////Range: 0x0006 to 0x0C80 Time = N * 1.25 msec	      1*1.25=7.5ms
	params.itvl_max=8;
	params.latency=0;
	params.supervision_timeout=300;//????3?��o?����o?��??Supervision timeout for the LE Link.Range: 0x000A to 0x0C80Time = connTimeout* 10 msecTime Range: 100 msec to 32 seconds
	int conn_idx;
	int rc;	
	uint8_t i;
	struct ble_hs_adv_fields fields;
	uint8_t ble_name[30];

	switch (event->type) {
	case BLE_GAP_EVENT_CONNECT:
		gap_evt.type = TKL_BLE_GAP_EVT_CONNECT;
		gap_evt.conn_handle = tuya_conn_handle;
		gap_evt.gap_event.connect.role = TKL_BLE_ROLE_SERVER;

		if (g_tlk_ble_gap_event_callback) {
			printf("[%s:%d]send event type:%d (TKL_BLE_GAP_EVT_CONNECT)\n", __func__, __LINE__, gap_evt.type);
			printf("[%s:%d]gap_evt.conn_handle :%d\r\n",  __func__, __LINE__, gap_evt.conn_handle);
			g_tlk_ble_gap_event_callback(&gap_evt);
		}
		return 0;
		
	case BLE_GAP_EVENT_DISCONNECT:
		gap_evt.type = TKL_BLE_GAP_EVT_DISCONNECT;
		gap_evt.conn_handle = tuya_conn_handle;
		gap_evt.gap_event.connect.role = TKL_BLE_ROLE_SERVER;

		if (g_tlk_ble_gap_event_callback) {
			printf("[%s:%d]send event type:%d (TKL_BLE_GAP_EVT_DISCONNECT)\n",  __func__, __LINE__, gap_evt.type);
			printf("[%s:%d]gap_evt.conn_handle :%d\r\n",  __func__, __LINE__, gap_evt.conn_handle);
			g_tlk_ble_gap_event_callback(&gap_evt);
		}

	    return 0;
	case BLE_GAP_EVENT_CONN_UPDATE:
		gap_evt.type = TKL_BLE_GAP_EVT_CONN_PARAM_UPDATE;
		gap_evt.result = 0;
		gap_evt.conn_handle = event->connect.conn_handle;
		// gap_evt.gap_event = 
		if (g_tlk_ble_gap_event_callback) {
			printf("[%s:%d]send event type:%d (TKL_BLE_GAP_EVT_CONN_PARAM_UPDATE)\n",  __func__, __LINE__, gap_evt.type);
			printf("[%s:%d]gap_evt.conn_handle :%d\r\n",  __func__, __LINE__, gap_evt.conn_handle);
			g_tlk_ble_gap_event_callback(&gap_evt);
		}
	    return 0;

	case BLE_GAP_EVENT_CONN_UPDATE_REQ:
		gap_evt.type = TKL_BLE_GAP_EVT_CONN_PARAM_REQ;
		gap_evt.result = 1;
		gap_evt.conn_handle = event->connect.conn_handle;
		gap_evt.gap_event.connect.conn_params.conn_interval_min = event->conn_update_req.self_params->itvl_min;
		gap_evt.gap_event.connect.conn_params.conn_interval_max = event->conn_update_req.self_params->itvl_max;
		gap_evt.gap_event.connect.conn_params.conn_latency = event->conn_update_req.self_params->latency;
		gap_evt.gap_event.connect.conn_params.conn_sup_timeout = event->conn_update_req.self_params->supervision_timeout;

		if (g_tlk_ble_gap_event_callback) {
			printf("[%s:%d]send event type:%d (TKL_BLE_GAP_EVT_CONN_PARAM_REQ)\n",  __func__, __LINE__, gap_evt.type);
			printf("[%s:%d]gap_evt.conn_handle :%d\r\n",  __func__, __LINE__, gap_evt.conn_handle);
			g_tlk_ble_gap_event_callback(&gap_evt);
		}
	    return 0;
	default:
	    return 0;
	}
}


static int gatt_svr_chr_write(struct os_mbuf *om, uint16_t min_len, uint16_t max_len,
	void *dst, uint16_t *len)
{
	uint16_t om_len;
	int rc;

	om_len = OS_MBUF_PKTLEN(om);
	if (om_len < min_len || om_len > max_len) {
		return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
	}

	rc = ble_hs_mbuf_to_flat(om, dst, max_len, len);
	if (rc != 0) {
		return BLE_ATT_ERR_UNLIKELY;
	}

	return 0;
}

static int gatt_svr_chr_indicate(uint16_t conn_handle, uint16_t chr_val_handle, const char *data, int len)
{
	int rc;
	struct os_mbuf *om = NULL;

	om = ble_hs_mbuf_from_flat((void *)data, (uint16_t)len);
	if(om == NULL)
		return -1;

	rc = ble_gattc_indicate_custom(conn_handle, chr_val_handle, om);
	if(rc)
		return -2;

	return 0;
}

static int ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle,
	struct ble_gatt_access_ctxt *ctxt, void *arg)
{
	
	int rc;
	uint16_t uuid;
	const int max_data_len = 1024;
	uint8_t data[max_data_len];
	uint16_t len = 0;
	uint8_t i=0;
	memset(data, 0, sizeof(data));
	uuid = ble_uuid_u16(ctxt->chr->uuid);
	printf("[%s:%d] ble_uuid_u16(ctxt->chr->uuid) >> uuid:%d\n", __func__, __LINE__, uuid);
	printf("[%s:%d] ctxt->chr->flags:%#x\n", __func__, __LINE__, ctxt->chr->flags);
	if(ctxt->chr->flags & BLE_GATT_CHR_F_WRITE) {
		rc = gatt_svr_chr_write(ctxt->om, 0, sizeof(data), data, &len);
		if(rc)	{
			return rc;
		}
		iot_printf("max_data_len=%d \n", max_data_len);
		iot_printf("Len=%d \n", len);
		iot_printf("att=");
		for(i=0;i<len;i++) {
			iot_printf("0x%x ", data[i]);
		}
		iot_printf("\n");

		if (recv_handler){
			recv_handler((unsigned char *)data, len);
		}

		if (g_tlk_ble_gatt_event_callback) {
			TKL_BLE_GATT_PARAMS_EVT_T event;
			memset(&event, 0, sizeof(TKL_BLE_GATT_PARAMS_EVT_T));
			event.result = 0;
			event.type = TKL_BLE_GATT_EVT_WRITE_REQ;
			event.conn_handle = tuya_conn_handle;
			char str_uuid_buf[128] = {0};
			if (ble_uuid_to_str(ctxt->chr->uuid, str_uuid_buf)) {
				event.gatt_event.write_report.char_handle = atoi(str_uuid_buf);
			} else {
				event.gatt_event.write_report.char_handle = ble_uuid_u16(ctxt->chr->uuid);;
			}
			event.gatt_event.write_report.report.p_data = data;
			event.gatt_event.write_report.report.length = len;
			printf("[%s:%d]conn_handle :%d \n", __func__, __LINE__, conn_handle);
			printf("[%s:%d]attr_handle :%d \n", __func__, __LINE__, attr_handle);
			printf("[%s:%d]tuya_conn_handle:%d \n", __func__, __LINE__, tuya_conn_handle);
			printf("[%s:%d]send gatt event type:%d (TKL_BLE_GATT_EVT_WRITE_REQ)\n", __func__, __LINE__, event.type);
			printf("[%s:%d]event.gatt_event.write_report.char_handle :%d\r\n", __func__, __LINE__, event.gatt_event.write_report.char_handle);
			g_tlk_ble_gatt_event_callback(&event);
		}

#if ATBM_BLE_SMART_APP
		if(((memcmp(data, "recv ok", strlen("recv ok"))) == 0) && (ble_smart_info.step == 4)){
			ble_smart_info.step = BLE_SMART_CFG_STATUS_END;
			ble_npl_sem_release(&hci_smt_sem);
		}

		if(ble_smart_info.step == BLE_SMART_CFG_STATUS_END){
			return 0;
		}

		switch(ble_smart_info.step)
		{
			case 0:
				if((memcmp(data,"ssid",strlen("ssid"))) == 0){
					if(len == 6){
						ble_smart_info.ssid_len = (data[5] - '0');
					}
					else if(len == 7){
						ble_smart_info.ssid_len = 10*(data[5] - '0') + (data[6] - '0');
					}

					iot_printf("ble ssid_len = %d\n",ble_smart_info.ssid_len);
					if(ble_smart_info.ssid_len > 32){					
						iot_printf("ble ssid_len too big error\n");
						ble_smart_info.step = BLE_SMART_CFG_STATUS_SSID_LEN_ERR;
						ble_npl_sem_release(&hci_smt_sem);
						break;
					}
					else {
						ble_smart_info.step =1;
					}
				}				
				break;

			case 1:
				if((ble_smart_info.ssid_cnt + len <= ble_smart_info.ssid_len)){
					memcpy(&ble_smart_info.ssid[ble_smart_info.ssid_cnt], data, len);
					ble_smart_info.ssid_cnt += len;
				}
				else{
					ble_smart_info.step = BLE_SMART_CFG_STATUS_SSID_ERR;
					ble_npl_sem_release(&hci_smt_sem);
					break;
				}
				if(ble_smart_info.ssid_cnt == ble_smart_info.ssid_len){
					ble_smart_info.step =2;
					iot_printf("ble ssid = %s\n", ble_smart_info.ssid);
				}				
				break;

			case 2:
				if((memcmp(data, "pwd", strlen("pwd"))) == 0){
					if(len == 5){
						ble_smart_info.pwd_len = (data[4] - '0');
					}
					else if(len == 6){
						ble_smart_info.pwd_len = 10*(data[4] - '0') + (data[5] - '0');
					}

					iot_printf("ble pwd_len = %d\n",ble_smart_info.pwd_len);

					if(ble_smart_info.pwd_len > 64){					
						iot_printf("ble pwd_len too big error\n");
						ble_smart_info.step = BLE_SMART_CFG_STATUS_PWD_LEN_ERR;
						ble_npl_sem_release(&hci_smt_sem);
					}
					else if((ble_smart_info.pwd_len < 5)&&(ble_smart_info.pwd_len > 0)){					
						iot_printf("ble pwd_len too short error\n");
						ble_smart_info.step = BLE_SMART_CFG_STATUS_PWD_LEN_ERR;
						ble_npl_sem_release(&hci_smt_sem);
					}
					else if(ble_smart_info.pwd_len == 0){
						iot_printf("ble pwd_len is empty\n");
						ble_smart_info.step =4;
					}
					else {
						ble_smart_info.step =3;
					}
				}				
				break;

			case 3:
				if((ble_smart_info.pwd_cnt + len <= ble_smart_info.pwd_len)){
					memcpy(&ble_smart_info.pwd[ble_smart_info.pwd_cnt], data, len);
					ble_smart_info.pwd_cnt += len;
				}
				else{
					ble_smart_info.step = BLE_SMART_CFG_STATUS_PWD_ERR;
					ble_npl_sem_release(&hci_smt_sem);
					break;
				}
				if(ble_smart_info.pwd_cnt == ble_smart_info.pwd_len){
					ble_smart_info.step =4;
					iot_printf("ble pwd = %s\n", ble_smart_info.ssid);
				}				
				break;

			default:
				break;
		}

		if(ble_smart_info.step == 5){
			iot_printf("connection, notify success\n");
			gatt_svr_chr_notify(conn_handle, blesmt_notify_handle, wifi_conn_ok, strlen(wifi_conn_ok));
		} else if(ble_smart_info.step == BLE_SMART_CFG_SSID_PWD_TRANS_END){   //wait
			iot_printf("connection, notify trans done\n");
			ble_npl_sem_release(&hci_smt_sem);
			//gatt_svr_chr_notify(conn_handle, blesmt_notify_handle, wifi_conn_ok, strlen(wifi_conn_ok));
		} else if(ble_smart_info.step == 4){
			iot_printf("connection, notify success\n");
			//ble_smart_info.step = BLE_SMART_CFG_SSID_PWD_TRANS_END;
			ble_npl_sem_release(&hci_smt_sem);
			//gatt_svr_chr_notify(conn_handle, blesmt_notify_handle, wifi_conn_ok, strlen(wifi_conn_ok));
		} else if(ble_smart_info.step >= BLE_SMART_CFG_STATUS_BUSY){
			iot_printf("connection, notify wait failed\n");
			gatt_svr_chr_notify(conn_handle, blesmt_notify_handle, wifi_conn_wait, strlen(wifi_conn_wait));
		}
#endif
	} else if (ctxt->chr->flags & BLE_GATT_CHR_F_READ) {
		memcpy(data, "resp", strlen("resp"));
		printf("[%s:%d]conn_handle :%d, attr_handle:%d\r\n", __func__, __LINE__, conn_handle, attr_handle);
		gatt_svr_chr_indicate(conn_handle, attr_handle, (char *)data, strlen("resp"));
	} else if (ctxt->chr->flags & BLE_GATT_CHR_F_NOTIFY) {
		memcpy(data, "ok", strlen("ok"));
		printf("[%s:%d]conn_handle :%d, attr_handle:%d\r\n", __func__, __LINE__, conn_handle, attr_handle);
		gatt_svr_chr_notify(conn_handle, attr_handle, data, strlen("ok"));
	}
return 0;
}

#if 0

#define BLE_USER_DATA_SVC_UUID16			0x181C
#define BLE_ATBM_SMART_DATA					0x2A8A
#define BLE_ATBM_SMART_NOTIFY				0x2A90

#define BLE_ATBM_GAP_SVR					0xBBB0
#define BLE_ATBM_GAP_SVR1					0xBBB1

static const char *ble_version = "nimble4.2";
static const char *firmware_info = "cronus_1.0";
static const char *software_info = "V1.0.0";
static const char* wifi_conn_ok ="ok";
static const char* wifi_conn_no ="no";
static const char* wifi_conn_wait ="wt";
extern sem_t sem_sock_sync;
extern char cmd_line[1600];

extern bool g_is_quit;

struct ble_smart_cfg_t  ble_smart_info;

static uint8_t ble_status = 0;
static bool ble_is_quit;
static int smart_cfg_start = 0;
static struct ble_npl_sem hci_smt_sem;
pAtbm_thread_t ble_smt_thread = NULL;
static uint16_t ble_conn_handle;
static char device_name[32] = {0};
static uint8_t blesmt_addr_type;
static uint16_t blesmt_notify_handle;
static uint16_t ble_svc_gatt_changed_val_handle;
static void blesmt_advertise(void);

ble_recv_handler recv_handler = NULL;


void atbm_print_bytes(const uint8_t *bytes, int len)
{
    int i;

    for (i = 0; i < len; i++) {
        MODLOG_DFLT(INFO, "%s0x%02x", i != 0 ? ":" : "", bytes[i]);
    }
}

void get_ble_addr(uint8_t* ble_addr)
{
	uint8_t *addr;
	//ble_hs_id_addr(BLE_ADDR_RANDOM,&addr,NULL);
	//iot_printf("addr %02hhx:%B2hhx:%B2hhx:%02hhx:%2hhx:%02hhxin",addr[0], addr[1], addr[2], addr[3], addr[4],addr[5]);
	
	ble_hs_id_addr(BLE_ADDR_PUBLIC,&addr, NULL);
	//iot_printf("pub addr %02hhx:%02hx:%2hx:%2hhx:%02hhx:%02hhx\n",addr[5],addr[4],addr[3],addr[2],addr[1],addr[0]);
	memcpy(ble_addr, addr, 6);
}

static SRAM_CODE void print_uuid(const ble_uuid_t *uuid)
{
    char buf[BLE_UUID_STR_LEN];

    ble_uuid_to_str(uuid, buf);

    iot_printf("%s", buf);
}

SRAM_CODE void atbm_print_addr(const void *addr)
{
    const uint8_t *u8p;

    u8p = addr;
    MODLOG_DFLT(INFO, "%02x:%02x:%02x:%02x:%02x:%02x",
                u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]);
}

void atbm_print_conn_desc(const struct ble_gap_conn_desc *desc)
{
    iot_printf("handle=%d our_ota_addr_type=%d our_ota_addr=",
                   desc->conn_handle, desc->our_ota_addr.type);
    atbm_print_addr(desc->our_ota_addr.val);
    iot_printf(" our_id_addr_type=%d our_id_addr=",
                   desc->our_id_addr.type);
    atbm_print_addr(desc->our_id_addr.val);
    iot_printf(" peer_ota_addr_type=%d peer_ota_addr=",
                   desc->peer_ota_addr.type);
    atbm_print_addr(desc->peer_ota_addr.val);
    iot_printf(" peer_id_addr_type=%d peer_id_addr=",
                   desc->peer_id_addr.type);
    atbm_print_addr(desc->peer_id_addr.val);
    iot_printf(" conn_itvl=%d conn_latency=%d supervision_timeout=%d "
                   "encrypted=%d authenticated=%d bonded=%d\n",
                   desc->conn_itvl, desc->conn_latency,
                   desc->supervision_timeout,
                   desc->sec_state.encrypted,
                   desc->sec_state.authenticated,
                   desc->sec_state.bonded);
}

static int gatt_svr_chr_write(struct os_mbuf *om, uint16_t min_len, uint16_t max_len,
                   void *dst, uint16_t *len)
{
    uint16_t om_len;
    int rc;

    om_len = OS_MBUF_PKTLEN(om);
    if (om_len < min_len || om_len > max_len) {
        return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
    }

    rc = ble_hs_mbuf_to_flat(om, dst, max_len, len);
    if (rc != 0) {
        return BLE_ATT_ERR_UNLIKELY;
    }

    return 0;
}

int gatt_svr_chr_notify(uint16_t conn_handle, uint16_t chr_val_handle, const char *data, int len)
{
	int rc;
	struct os_mbuf *om = NULL;

	om = ble_hs_mbuf_from_flat((void *)data, (uint16_t)len);
	if(om == NULL)
		return -1;
	rc = ble_gattc_notify_custom(conn_handle, chr_val_handle, om);
	if(rc)
		return -2;
	return 0;
}
static int gatt_svr_chr_indicate(uint16_t conn_handle, uint16_t chr_val_handle, const char *data, int len)
{
	int rc;
	struct os_mbuf *om = NULL;

	om = ble_hs_mbuf_from_flat((void *)data, (uint16_t)len);
	if(om == NULL)
		return -1;

	rc = ble_gattc_indicate_custom(conn_handle, chr_val_handle, om);
	if(rc)
		return -2;

	return 0;
}

static int ble_svc_gap_access(uint16_t conn_handle, uint16_t attr_handle,
                   struct ble_gatt_access_ctxt *ctxt, void *arg)
{
    uint16_t uuid16;
    int rc;

    uuid16 = ble_uuid_u16(ctxt->chr->uuid);
    assert(uuid16 != 0);

    switch (uuid16) {
    case BLE_SVC_GAP_CHR_UUID16_DEVICE_NAME:
        if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
            rc = os_mbuf_append(ctxt->om, device_name, strlen(device_name));
        } else {
            assert(0);
        }
        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;

    default:
        assert(0);
        return BLE_ATT_ERR_UNLIKELY;
    }
	return 0;
}

static int ble_svc_dis_access(uint16_t conn_handle, uint16_t attr_handle,
                   struct ble_gatt_access_ctxt *ctxt, void *arg)
{
    uint16_t uuid    = ble_uuid_u16(ctxt->chr->uuid);
    const char *info = NULL;
	int rc;

	switch(uuid) {
	case BLE_SVC_DIS_CHR_UUID16_MANUFACTURER_NAME:
		info = ble_version;
		break;
	case BLE_SVC_DIS_CHR_UUID16_FIRMWARE_REVISION:
		info = firmware_info;
		break;
	case BLE_SVC_DIS_CHR_UUID16_SOFTWARE_REVISION:
		info = software_info;
		break;
    default:
		assert(0);
		return BLE_ATT_ERR_UNLIKELY;
	}
    if (info != NULL) {
		rc = os_mbuf_append(ctxt->om, info, strlen(info));
		return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
    }
	return 0;
}
#define BUFFER_SIZE 4096

SRAM_CODE void 
ble_print_adv_fields(const struct ble_hs_adv_fields *fields)
{
    uint8_t *u8p;
    int i;

    if (fields->flags != 0) {
        iot_printf("    flags=0x%02x:\n", fields->flags);

        if (!(fields->flags & BLE_HS_ADV_F_DISC_LTD) &&
                !(fields->flags & BLE_HS_ADV_F_DISC_GEN)) {
                iot_printf("        Non-discoverable mode\n");
        }

        if (fields->flags & BLE_HS_ADV_F_DISC_LTD) {
                iot_printf("        Limited discoverable mode\n");
        }

        if (fields->flags & BLE_HS_ADV_F_DISC_GEN) {
                iot_printf("        General discoverable mode\n");
        }

        if (fields->flags & BLE_HS_ADV_F_BREDR_UNSUP) {
                iot_printf("        BR/EDR not supported\n");
        }
    }

    if (fields->uuids16 != NULL) {
        iot_printf("    uuids16(%scomplete)=",
                       fields->uuids16_is_complete ? "" : "in");
        for (i = 0; i < fields->num_uuids16; i++) {
            print_uuid(&fields->uuids16[i].u);
            iot_printf(" ");
        }
        iot_printf("\n");
    }

    if (fields->uuids32 != NULL) {
        iot_printf("    uuids32(%scomplete)=",
                       fields->uuids32_is_complete ? "" : "in");
        for (i = 0; i < fields->num_uuids32; i++) {
            print_uuid(&fields->uuids32[i].u);
            iot_printf(" ");
        }
        iot_printf("\n");
    }

    if (fields->uuids128 != NULL) {
        iot_printf("    uuids128(%scomplete)=",
                       fields->uuids128_is_complete ? "" : "in");
        for (i = 0; i < fields->num_uuids128; i++) {
            print_uuid(&fields->uuids128[i].u);
            iot_printf(" ");
        }
        iot_printf("\n");
    }

    if (fields->name != NULL) {
		int i=0;
        iot_printf("    name(%scomplete)=",
                       fields->name_is_complete ? "" : "in");
        for(i=0;i<fields->name_len;i++){
			//putchar(((char *)fields->name)[i]);
			iot_printf("%c", ((char *)fields->name)[i]);
        }
		
        iot_printf("\n");
    }

    if (fields->tx_pwr_lvl_is_present) {
        iot_printf("    tx_pwr_lvl=%d\n", fields->tx_pwr_lvl);
    }

    if (fields->slave_itvl_range != NULL) {
        iot_printf("    slave_itvl_range=");
        atbm_print_bytes(fields->slave_itvl_range,
                            BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN);
        iot_printf("\n");
    }

    if (fields->svc_data_uuid16 != NULL) {
        iot_printf("    svc_data_uuid16=");
        atbm_print_bytes(fields->svc_data_uuid16,
                            fields->svc_data_uuid16_len);
        iot_printf("\n");
    }

    if (fields->public_tgt_addr != NULL) {
        iot_printf("    public_tgt_addr=");
        u8p = fields->public_tgt_addr;
        for (i = 0; i < fields->num_public_tgt_addrs; i++) {
            atbm_print_addr(u8p);
            u8p += BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN;
        }
        iot_printf("\n");
    }

    if (fields->appearance_is_present) {
        iot_printf("    appearance=0x%04x\n", fields->appearance);
    }

    if (fields->adv_itvl_is_present) {
        iot_printf("    adv_itvl=0x%04x\n", fields->adv_itvl);
    }

    if (fields->svc_data_uuid32 != NULL) {
        iot_printf("    svc_data_uuid32=");
        atbm_print_bytes(fields->svc_data_uuid32,
                             fields->svc_data_uuid32_len);
        iot_printf("\n");
    }

    if (fields->svc_data_uuid128 != NULL) {
        iot_printf("    svc_data_uuid128=");
        atbm_print_bytes(fields->svc_data_uuid128,
                            fields->svc_data_uuid128_len);
        iot_printf("\n");
    }

    if (fields->uri != NULL) {
        iot_printf("    uri=");
        atbm_print_bytes(fields->uri, fields->uri_len);
        iot_printf("\n");
    }

    if (fields->mfg_data != NULL) {
        iot_printf("    mfg_data=");
        atbm_print_bytes(fields->mfg_data, fields->mfg_data_len);
        iot_printf("\n");
    }
}

int ble_startup_indication(unsigned char* data)
{
	
}
void atbm_ioctl_ble_smt_event_async(uint8_t* event_buffer, uint16_t event_len)
{
	
}

static int ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle,
                    struct ble_gatt_access_ctxt *ctxt, void *arg)
{
	int rc;
    uint16_t uuid;
	uint8_t data[255] = {0};
	uint16_t len = 0;
	uint8_t i=0;

	uuid = ble_uuid_u16(ctxt->chr->uuid);
	if(uuid == BLE_ATBM_SMART_DATA) {
		rc = gatt_svr_chr_write(ctxt->om, 0, 255, data, &len);
		if(rc){
			return rc;
		}
		iot_printf("Len=%d step %d\n", len, ble_smart_info.step);
		iot_printf("att=");
		for(i=0;i<len;i++)
		{
			iot_printf("0x%x ", data[i]);
		}
		iot_printf("\n");

		if (recv_handler){
			recv_handler((unsigned char *)data, len);
		}

		if (g_tlk_ble_gatt_event_callback) {
			TKL_BLE_GATT_PARAMS_EVT_T event;
			memset(&event, 0, sizeof(TKL_BLE_GATT_PARAMS_EVT_T));
			event.result = 0;
			event.type = TKL_BLE_GATT_EVT_WRITE_REQ;
			event.conn_handle = conn_handle;
			event.gatt_event.write_report.char_handle = uuid;
			event.gatt_event.write_report.report.p_data = data;
			event.gatt_event.write_report.report.length = len;
			g_tlk_ble_gatt_event_callback(&event);
		}

		#if ATBM_BLE_SMART_APP
		if(((memcmp(data, "recv ok", strlen("recv ok"))) == 0) && (ble_smart_info.step == 4)){
			ble_smart_info.step = BLE_SMART_CFG_STATUS_END;
			ble_npl_sem_release(&hci_smt_sem);
		}

		if(ble_smart_info.step == BLE_SMART_CFG_STATUS_END){
			return 0;
		}
		
		switch(ble_smart_info.step)
		{
			case 0:
				if((memcmp(data,"ssid",strlen("ssid"))) == 0){
					if(len == 6){
						ble_smart_info.ssid_len = (data[5] - '0');
					}
					else if(len == 7){
						ble_smart_info.ssid_len = 10*(data[5] - '0') + (data[6] - '0');
					}

					iot_printf("ble ssid_len = %d\n",ble_smart_info.ssid_len);
					if(ble_smart_info.ssid_len > 32){					
						iot_printf("ble ssid_len too big error\n");
						ble_smart_info.step = BLE_SMART_CFG_STATUS_SSID_LEN_ERR;
						ble_npl_sem_release(&hci_smt_sem);
						break;
					}
					else {
						ble_smart_info.step =1;
					}
				}				
				break;
				
			case 1:
				if((ble_smart_info.ssid_cnt + len <= ble_smart_info.ssid_len)){
					memcpy(&ble_smart_info.ssid[ble_smart_info.ssid_cnt], data, len);
					ble_smart_info.ssid_cnt += len;
				}
				else{
					ble_smart_info.step = BLE_SMART_CFG_STATUS_SSID_ERR;
					ble_npl_sem_release(&hci_smt_sem);
					break;
				}
				if(ble_smart_info.ssid_cnt == ble_smart_info.ssid_len){
					ble_smart_info.step =2;
					iot_printf("ble ssid = %s\n", ble_smart_info.ssid);
				}				
				break;

			case 2:
				if((memcmp(data, "pwd", strlen("pwd"))) == 0){
					if(len == 5){
						ble_smart_info.pwd_len = (data[4] - '0');
					}
					else if(len == 6){
						ble_smart_info.pwd_len = 10*(data[4] - '0') + (data[5] - '0');
					}

					iot_printf("ble pwd_len = %d\n",ble_smart_info.pwd_len);

					if(ble_smart_info.pwd_len > 64){					
						iot_printf("ble pwd_len too big error\n");
						ble_smart_info.step = BLE_SMART_CFG_STATUS_PWD_LEN_ERR;
						ble_npl_sem_release(&hci_smt_sem);
					}
					else if((ble_smart_info.pwd_len < 5)&&(ble_smart_info.pwd_len > 0)){					
						iot_printf("ble pwd_len too short error\n");
						ble_smart_info.step = BLE_SMART_CFG_STATUS_PWD_LEN_ERR;
						ble_npl_sem_release(&hci_smt_sem);
					}
					else if(ble_smart_info.pwd_len == 0){
						iot_printf("ble pwd_len is empty\n");
						ble_smart_info.step =4;
					}
					else {
						ble_smart_info.step =3;
					}
				}				
				break;
				
			case 3:
				if((ble_smart_info.pwd_cnt + len <= ble_smart_info.pwd_len)){
					memcpy(&ble_smart_info.pwd[ble_smart_info.pwd_cnt], data, len);
					ble_smart_info.pwd_cnt += len;
				}
				else{
					ble_smart_info.step = BLE_SMART_CFG_STATUS_PWD_ERR;
					ble_npl_sem_release(&hci_smt_sem);
					break;
				}
				if(ble_smart_info.pwd_cnt == ble_smart_info.pwd_len){
					ble_smart_info.step =4;
					iot_printf("ble pwd = %s\n", ble_smart_info.ssid);
				}				
				break;
				
			default:
				break;
		}

		if(ble_smart_info.step == 5){
			iot_printf("connection, notify success\n");
			gatt_svr_chr_notify(conn_handle, blesmt_notify_handle, wifi_conn_ok, strlen(wifi_conn_ok));
		}
		else if(ble_smart_info.step == BLE_SMART_CFG_SSID_PWD_TRANS_END){   //wait
			iot_printf("connection, notify trans done\n");
			ble_npl_sem_release(&hci_smt_sem);
			//gatt_svr_chr_notify(conn_handle, blesmt_notify_handle, wifi_conn_ok, strlen(wifi_conn_ok));
		}
		else if(ble_smart_info.step == 4){
			iot_printf("connection, notify success\n");
			//ble_smart_info.step = BLE_SMART_CFG_SSID_PWD_TRANS_END;
			ble_npl_sem_release(&hci_smt_sem);
			//gatt_svr_chr_notify(conn_handle, blesmt_notify_handle, wifi_conn_ok, strlen(wifi_conn_ok));
		}
		else if(ble_smart_info.step >= BLE_SMART_CFG_STATUS_BUSY){
				iot_printf("connection, notify wait failed\n");
			gatt_svr_chr_notify(conn_handle, blesmt_notify_handle, wifi_conn_wait, strlen(wifi_conn_wait));
		}
		#endif
	}

	
	
	return 0;
}

static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
#if  0
    {
        /* Service: GAP */
        .type = BLE_GATT_SVC_TYPE_PRIMARY,
        .uuid = BLE_UUID16_DECLARE(BLE_SVC_GAP_UUID16),
        .characteristics = (struct ble_gatt_chr_def[]) { {
            /* Characteristic: Heart-rate measurement */
            .uuid = BLE_UUID16_DECLARE(BLE_SVC_GAP_CHR_UUID16_DEVICE_NAME),
            .access_cb = ble_svc_gap_access,
            .flags = BLE_GATT_CHR_F_READ,
        },  {
            0, /* No more characteristics in this service */
        }, }
    },
#endif
    {
        /* Service: Device Information */
        .type = BLE_GATT_SVC_TYPE_PRIMARY,
        .uuid = BLE_UUID16_DECLARE(BLE_SVC_DIS_UUID16),
        .characteristics = (struct ble_gatt_chr_def[]) { {
            /* Characteristic: * Manufacturer name */
            .uuid = BLE_UUID16_DECLARE(BLE_SVC_DIS_CHR_UUID16_MANUFACTURER_NAME),
            .access_cb = ble_svc_dis_access,
            .flags = BLE_GATT_CHR_F_READ,
        }, {
            /* Characteristic: Model number string */
            .uuid = BLE_UUID16_DECLARE(BLE_SVC_DIS_CHR_UUID16_FIRMWARE_REVISION),
            .access_cb = ble_svc_dis_access,
            .flags = BLE_GATT_CHR_F_READ,
        },{
            /* Characteristic: Model number string */
            .uuid = BLE_UUID16_DECLARE(BLE_SVC_DIS_CHR_UUID16_SOFTWARE_REVISION),
            .access_cb = ble_svc_dis_access,
            .flags = BLE_GATT_CHR_F_READ,
        }, {
            0, /* No more characteristics in this service */
        }, }
    },
    
	{
		/* Service: GATT */
		.type = BLE_GATT_SVC_TYPE_PRIMARY,
		.uuid = BLE_UUID16_DECLARE(BLE_USER_DATA_SVC_UUID16),
		.characteristics = (struct ble_gatt_chr_def[]) { {
			.uuid = BLE_UUID16_DECLARE(BLE_ATBM_SMART_DATA),
			.access_cb = ble_svc_gatt_access,
			.flags = BLE_GATT_CHR_F_WRITE,
		}, {
			.uuid = BLE_UUID16_DECLARE(BLE_ATBM_SMART_NOTIFY),
			.access_cb = ble_svc_gatt_access,
			.val_handle = &blesmt_notify_handle,
			.flags = BLE_GATT_CHR_F_NOTIFY,
		}, {
			0, /* No more characteristics in this service */
		}, }
	},

    {
        0, /* No more services */
    },
};

void ble_smart_gatt_svcs_init(void)
{
	int rc;
printf("[%s:%d] \n", __func__, __LINE__);
    ble_svc_gap_init();
	printf("[%s:%d] \n", __func__, __LINE__);
    ble_svc_gatt_init();
	printf("[%s:%d] \n", __func__, __LINE__);
    rc = ble_gatts_count_cfg(gatt_svr_svcs);
    if (rc != 0) {
        return;
    }
	printf("[%s:%d] \n", __func__, __LINE__);
    rc = ble_gatts_add_svcs(gatt_svr_svcs);
    if (rc != 0) {
        return;
    }
	printf("[%s:%d] \n", __func__, __LINE__);
    rc = ble_svc_gap_device_name_set(device_name);
    assert(rc == 0);
	printf("[%s:%d] \n", __func__, __LINE__);
}

int ble_slave_gap_event(struct ble_gap_event *event, void *arg)
{
	TKL_BLE_GAP_PARAMS_EVT_T gap_evt;
	struct ble_gap_conn_desc desc;
	struct ble_sm_io pkey;
	/* Connection handle */
	//uint16_t conn_handle=1;
	struct ble_gap_upd_params params;
	params.itvl_min=7;////Range: 0x0006 to 0x0C80 Time = N * 1.25 msec	      1*1.25=7.5ms
	params.itvl_max=8;
	params.latency=0;
	params.supervision_timeout=300;//????3?��o?����o?��??Supervision timeout for the LE Link.Range: 0x000A to 0x0C80Time = connTimeout* 10 msecTime Range: 100 msec to 32 seconds
	int conn_idx;
	int rc;	
	uint8_t i;
	struct ble_hs_adv_fields fields;
	uint8_t ble_name[30];
	iot_printf("ble_slave_gap_event->type=%d\n",event->type);
	switch (event->type) {
	case BLE_GAP_EVENT_CONNECT:
		iot_printf("connection %s; status=%d ",
		               event->connect.status == 0 ? "established" : "failed",
		               event->connect.status);
		if (event->connect.status == 0) {
			ble_status=ATBM_BLE_STATUS_CONNECT;
			ble_att_set_preferred_mtu(255);
			rc = ble_gattc_exchange_mtu(event->connect.conn_handle, NULL, NULL);
//			ble_gap_update_params(event->connect.conn_handle, &params);
		    //rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
		    //assert(rc == 0);
		    //print_conn_desc(&desc);
		    //btshell_conn_add(&desc);
		    iot_printf("connection, handle=%d\n",event->connect.conn_handle);
		    ble_conn_handle = event->connect.conn_handle;
		}
		else {
			iot_printf("Connection failed; resume advertising\n");
			/* Connection failed; resume advertising */
			blesmt_advertise();
		}
		gap_evt.type = TKL_BLE_GAP_EVT_CONNECT;
		gap_evt.result = event->connect.status == 0 ? 1 : 0;
		gap_evt.conn_handle = event->connect.conn_handle;

		if (g_tlk_ble_gap_event_callback) {
			g_tlk_ble_gap_event_callback(&gap_evt);
		}
		return 0;
		
	case BLE_GAP_EVENT_DISCONNECT:
		ble_status=ATBM_BLE_STATUS_IDLE;
	    iot_printf("disconnect; reason=%d \n", event->disconnect.reason);
	    //print_conn_desc(&event->disconnect.conn);
	    if(!ble_is_quit)
	    	blesmt_advertise();
	    //conn_idx = btshell_conn_find_idx(event->disconnect.conn.conn_handle);
	    if (conn_idx != -1) {
	       //btshell_conn_delete_idx(conn_idx);
	    }

		gap_evt.type = TKL_BLE_GAP_EVT_DISCONNECT;
		gap_evt.result = 1;
		// gap_evt.conn_handle = event->connect.conn_handle;

		if (g_tlk_ble_gap_event_callback) {
			g_tlk_ble_gap_event_callback(&gap_evt);
		}

	    return 0;
#if (MYNEWT_VAL_BLE_EXT_ADV)
	case BLE_GAP_EVENT_EXT_DISC:
	    btshell_decode_event_type(&event->ext_disc, arg);
	    return 0;
#endif
	case BLE_GAP_EVENT_DISC:
		#if 1
			//if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) {
				//return 0;
			//}
			
			ble_hs_adv_parse_fields(&fields, event->disc.data, event->disc.length_data);
			if(fields.name && fields.name_len){

				memcpy(ble_name, fields.name, fields.name_len);
				ble_name[fields.name_len]=0;
				iot_printf("\n********************ble scan adv data*****************************\n");
				iot_printf("ble_name:%s\n",ble_name);
				//if(0 == memcmp(ble_scan_show_name, fields.name, fields.name_len))
				{
					iot_printf("received advertisement; event_type=%d rssi=%d "
								   "addr_type=%d addr=", event->disc.event_type,
								   event->disc.rssi, event->disc.addr.type);
					atbm_print_addr(event->disc.addr.val);
					iot_printf(" fields:\n");
					ble_print_adv_fields(&fields);
					iot_printf("\n");
				}
				iot_printf("\n********************end*****************************\n");
			}	
	        /*
	         * There is no adv data to print in case of connectable
	         * directed advertising
	         */
	        if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) {
	                iot_printf("\nConnectable directed advertising event\n");
	                return 0;
	        }
	#endif
	    return 0;

	case BLE_GAP_EVENT_CONN_UPDATE:
	    iot_printf("connection updated; status=%d ",
	                   event->conn_update.status);
	    rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc);
	    assert(rc == 0);
	    //print_conn_desc(&desc);
		iot_printf(" conn_itvl=%d conn_latency=%d supervision_timeout=%d "
					   "encrypted=%d authenticated=%d bonded=%d\n",
					   desc.conn_itvl, desc.conn_latency,
					   desc.supervision_timeout,
					   desc.sec_state.encrypted,
					   desc.sec_state.authenticated,
					   desc.sec_state.bonded);
		gap_evt.type = TKL_BLE_GAP_EVT_CONN_PARAM_UPDATE;
		gap_evt.result = rc == 0 ? 1 : 0;
		gap_evt.conn_handle = event->connect.conn_handle;
		// gap_evt.gap_event = 
		if (g_tlk_ble_gap_event_callback) {
			g_tlk_ble_gap_event_callback(&gap_evt);
		}
	    return 0;

	case BLE_GAP_EVENT_CONN_UPDATE_REQ:
	    iot_printf("connection update request\n");
	    *event->conn_update_req.self_params =
	        *event->conn_update_req.peer_params;

		gap_evt.type = TKL_BLE_GAP_EVT_CONN_PARAM_REQ;
		gap_evt.result = 1;
		gap_evt.conn_handle = event->connect.conn_handle;
		gap_evt.gap_event.connect.conn_params.conn_interval_min = event->conn_update_req.self_params->itvl_min;
		gap_evt.gap_event.connect.conn_params.conn_interval_max = event->conn_update_req.self_params->itvl_max;
		gap_evt.gap_event.connect.conn_params.conn_latency = event->conn_update_req.self_params->latency;
		gap_evt.gap_event.connect.conn_params.conn_sup_timeout = event->conn_update_req.self_params->supervision_timeout;

		if (g_tlk_ble_gap_event_callback) {
			g_tlk_ble_gap_event_callback(&gap_evt);
		}
	    return 0;

	case BLE_GAP_EVENT_PASSKEY_ACTION:
	    iot_printf("passkey action event; action=%d",
	                   event->passkey.params.action);
	    if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
	        iot_printf(" numcmp=%lu",
	                       (unsigned long)event->passkey.params.numcmp);
	    }else{
	        if(event->passkey.params.action == BLE_SM_IOACT_INPUT){
	            pkey.action = BLE_SM_IOACT_INPUT;
			}

		}
	    iot_printf("\n");
	    return 0;


	case BLE_GAP_EVENT_DISC_COMPLETE:
	    ble_status=ATBM_BLE_STATUS_IDLE;
	    iot_printf("discovery complete; reason=%d\n",
	                   event->disc_complete.reason);
	    return 0;

	case BLE_GAP_EVENT_ADV_COMPLETE:
#if (MYNEWT_VAL_BLE_EXT_ADV)
	    iot_printf("advertise complete; reason=%d, instance=%u, handle=%d\n",
	                   event->adv_complete.reason, event->adv_complete.instance,
	                   event->adv_complete.conn_handle);

	    ext_adv_restart[event->adv_complete.instance].conn_handle =
	        event->adv_complete.conn_handle;
#else
	    iot_printf("advertise complete; reason=%d\n",
	                   event->adv_complete.reason);
#endif
	    return 0;

	case BLE_GAP_EVENT_ENC_CHANGE:
	    iot_printf("encryption change event; status=%d ",
	                   event->enc_change.status);
	    rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
	    assert(rc == 0);
	    //print_conn_desc(&desc);
	    return 0;

	case BLE_GAP_EVENT_NOTIFY_RX:
	    iot_printf("notification rx event; attr_handle=%d indication=%d "
	                   "len=%d data=",
	                   event->notify_rx.attr_handle,
	                   event->notify_rx.indication,
	                   OS_MBUF_PKTLEN(event->notify_rx.om));

	   // print_mbuf(event->notify_rx.om);
	    iot_printf("\n");
	    return 0;

	case BLE_GAP_EVENT_NOTIFY_TX:
	    iot_printf("notification tx event; status=%d attr_handle=%d "
	                   "indication=%d\n",
	                   event->notify_tx.status,
	                   event->notify_tx.attr_handle,
	                   event->notify_tx.indication);
	    return 0;

	case BLE_GAP_EVENT_SUBSCRIBE:
	    iot_printf("subscribe event; conn_handle=%d attr_handle=%d "
	                   "reason=%d prevn=%d curn=%d previ=%d curi=%d\n",
	                   event->subscribe.conn_handle,
	                   event->subscribe.attr_handle,
	                   event->subscribe.reason,
	                   event->subscribe.prev_notify,
	                   event->subscribe.cur_notify,
	                   event->subscribe.prev_indicate,
	                   event->subscribe.cur_indicate);
		#if 1
	    if(ble_svc_gatt_changed_val_handle==event->subscribe.attr_handle)
	    {
	    		//log ?aindicate����?��?Tsubscribe event; conn_handle=1 attr_handle=10 reason=1 prevn=0 curn=0 previ=0 curi=1
	    		//log1?indicate����?��?Tsubscribe event; conn_handle=1 attr_handle=10 reason=1 prevn=0 curn=0 previ=1 curi=0
		    if((event->subscribe.prev_indicate==0)&&(event->subscribe.cur_indicate==1))
		    {	   
			    char* ble_indicate ="send indicate";
			     iot_printf("ble_svc_gatt_changed_val_handle=%d\n",
			                   ble_svc_gatt_changed_val_handle);
			    rc=gatt_svr_chr_indicate(ble_conn_handle, ble_svc_gatt_changed_val_handle, ble_indicate, strlen(ble_indicate));
			    assert(rc == 0);
		    }
	    }
		#endif
	    return 0;

	case BLE_GAP_EVENT_MTU:
	    iot_printf("mtu update event; conn_handle=%d cid=%d mtu=%d\n",
	                   event->mtu.conn_handle,
	                   event->mtu.channel_id,
	                   event->mtu.value);
	    return 0;

	case BLE_GAP_EVENT_IDENTITY_RESOLVED:
	    iot_printf("identity resolved ");
	    rc = ble_gap_conn_find(event->identity_resolved.conn_handle, &desc);
	    assert(rc == 0);
	    //print_conn_desc(&desc);
	    return 0;

	case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE:
	    iot_printf("PHY update complete; status=%d, conn_handle=%d "
	                   " tx_phy=%d, rx_phy=%d\n",
	                   event->phy_updated.status,
	                   event->phy_updated.conn_handle,
	                   event->phy_updated.tx_phy,
	                   event->phy_updated.rx_phy);
	    return 0;

	case BLE_GAP_EVENT_REPEAT_PAIRING:
	    /* We already have a bond with the peer, but it is attempting to
	     * establish a new secure link.  This app sacrifices security for
	     * convenience: just throw away the old bond and accept the new link.
	     */

	    /* Delete the old bond. */
	    rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
	    assert(rc == 0);
	    ble_store_util_delete_peer(&desc.peer_id_addr);

	    /* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should
	     * continue with the pairing operation.
	     */
	    return BLE_GAP_REPEAT_PAIRING_RETRY;

	default:
	    return 0;
	}
}

static void blesmt_advertise(void)
{
    struct ble_gap_adv_params adv_params;
    struct ble_hs_adv_fields fields;
	ble_uuid16_t uuids16[2];
	uint8_t mfg_data[3] = {0xAB, 0xAB, 0xA0};
	int rc;

    memset(&fields, 0, sizeof(fields));	
	
    fields.name = (uint8_t *)device_name;
    fields.name_len = strlen(device_name);
    fields.name_is_complete = 1;

	uuids16[0].u.type = BLE_UUID_TYPE_16;
	uuids16[0].value = BLE_ATBM_GAP_SVR;
	uuids16[1].u.type = BLE_UUID_TYPE_16;
	uuids16[1].value = BLE_ATBM_GAP_SVR1;
	fields.uuids16 = &uuids16[0];
	fields.num_uuids16 = 2;
	fields.uuids16_is_complete = 1;

	fields.mfg_data = mfg_data;
	fields.mfg_data_len = 3;
	
    rc = ble_gap_adv_set_fields(&fields);
    if (rc != 0) {
        iot_printf("[%s:%d] error setting advertisement data; rc=%d\n", __func__, __LINE__, rc);
        return;
    }
	struct ble_hs_adv_fields adv_fields;
	ble_uuid16_t uuids16_rsp[2];
	uint8_t mfg_rsp_data[3] = {0xff, 0xcc, 0xdd};
	memset(&adv_fields, 0, sizeof(adv_fields));	

	adv_fields.name = (uint8_t *)device_name;
	adv_fields.name_len = strlen(device_name);
	adv_fields.name_is_complete = 1;

	uuids16_rsp[0].u.type = BLE_UUID_TYPE_16;
	uuids16_rsp[0].value = 0xccc0;
	uuids16_rsp[1].u.type = BLE_UUID_TYPE_16;
	uuids16_rsp[1].value = 0xddd0;
	adv_fields.uuids16 = &uuids16_rsp[0];
	adv_fields.num_uuids16 = 2;
	adv_fields.uuids16_is_complete = 1;
	adv_fields.mfg_data = mfg_data;
	adv_fields.mfg_data_len = 3;
	rc=ble_gap_adv_rsp_set_fields(&adv_fields);
	 if (rc != 0) {
	    iot_printf("[%s:%d] error setting advertisement data; rc=%d\n", __func__, __LINE__, rc);
	    return;
	}
    memset(&adv_params, 0, sizeof(adv_params));
    adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
    adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;

	adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
    adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
	// adv_params.itvl_min = p_adv_params->adv_interval_min;
	// adv_params.itvl_max = p_adv_params->adv_interval_max;
	adv_params.channel_map = g_tkl_ble_gatt_adv_param.adv_channel_map;


	if(g_tkl_ble_gatt_adv_param.direct_addr.type == TKL_BLE_GAP_ADDR_TYPE_PUBLIC)
		blesmt_addr_type = BLE_OWN_ADDR_PUBLIC;
	else if(g_tkl_ble_gatt_adv_param.direct_addr.type == TKL_BLE_GAP_ADDR_TYPE_RANDOM)
		blesmt_addr_type = BLE_OWN_ADDR_RANDOM;

    rc = ble_gap_adv_start(blesmt_addr_type, NULL, BLE_HS_FOREVER,
                           		&adv_params, ble_slave_gap_event, NULL);
	if(!rc)
		ble_status=ATBM_BLE_STATUS_ADVERTISE;
    if (rc != 0) {
		printf("[%s:%d] error enabling advertisement; rc=%d\n", __func__, __LINE__, rc);
        // iot_printf("error enabling advertisement; rc=%d\n", rc);
        return;
    }	
}

static int ble_smart_cfg_task(void* param)
{
	int rc;
	int wifi_connected_status = 0;
	uint8_t atbm_ble_addr[6];
	char *name="iQOO";
	smart_cfg_start = 1;
	g_is_quit=0;
	ble_is_quit=0;
	ble_npl_time_t wifi_connected_start = 0;
	ble_npl_time_t wifi_connected_cur = 0;

	ble_npl_sem_init(&hci_smt_sem, 0);

	//	rc = ble_hs_id_infer_auto(0, &blesmt_addr_type);
	//	assert(rc == 0);
	blesmt_addr_type = BLE_OWN_ADDR_PUBLIC;
	ble_gap_set_default_tx_power(0);
	/* Begin advertising */
	blesmt_advertise();
	//ble_start_scan(name);
	get_ble_addr(atbm_ble_addr);
	iot_printf("pub addr %02hhx:%02hx:%2hx:%2hhx:%02hhx:%02hhx\n",atbm_ble_addr[5],atbm_ble_addr[4],atbm_ble_addr[3],atbm_ble_addr[2],atbm_ble_addr[1],atbm_ble_addr[0]);
#if ATBM_BLE_SMART_APP
	while (!ble_is_quit) {
		//iot_printf(" ble_smart_cfg_task wait... step %d\n", ble_smart_info.step);

		if (ble_smart_info.step != BLE_SMART_CFG_SSID_PWD_TRANS_END) {
			rc = ble_npl_sem_pend(&hci_smt_sem, ble_npl_time_ms_to_ticks32(1000));//BLE_SMART_CFG_TIMEOUT_MS  1000ms
		}
		else {
			//rc = ble_npl_sem_pend(&hci_smt_sem, ble_npl_time_ms_to_ticks32(1000));
			sleep(1);
			rc = 0;
		}
		
		if (rc == 0) {
			if (ble_smart_info.step == 4) {
				iot_printf("ble smart cfg connect ap! ssid:%s pwd:%s \n", ble_smart_info.ssid, ble_smart_info.pwd);
				wifi_connected_start = ble_npl_time_get();
				wifi_connected_start = ble_npl_time_ticks_to_ms32(wifi_connected_start);
				ble_smart_cfg_indication(BLE_SMART_CFG_SSID_PWD_TRANS_END, &ble_smart_info);
				ble_smart_info.step = BLE_SMART_CFG_SSID_PWD_TRANS_END;
				//break;
			}
			else if (ble_smart_info.step == BLE_SMART_CFG_SSID_PWD_TRANS_END) {

				//check wifi connect status				 
				//	ble_smart_cfg_indication(BLE_SMART_CFG_STATUS_END, &ble_smart_info);
				wifi_connected_status = get_wifi_wpa_status();
				iot_printf("BLE_SMART_CFG_SSID_PWD_TRANS_END!wifi_connected_status:%d \n", wifi_connected_status);
				if (wifi_connected_status == 1) {
					ble_smart_info.step = BLE_SMART_CFG_STATUS_END;
					gatt_svr_chr_notify(ble_conn_handle, blesmt_notify_handle, wifi_conn_ok, strlen(wifi_conn_ok));
					break;
				}

				//break;
			}
			else if (ble_smart_info.step == BLE_SMART_CFG_STATUS_END) {
				iot_printf("### ble smart cfg sucess!\n");
				break;
			}
			else {
				assert(ble_smart_info.step >= BLE_SMART_CFG_STATUS_BUSY);
				iot_printf("ble smart cfg err(0x%X)!\n", ble_smart_info.step);
				break;
			}
		}
		/*
		else {
			iot_printf("ble smart cfg timeout!\n");
			ble_smart_cfg_indication(BLE_SMART_CFG_STATUS_TIMEOUT, NULL);
			break;
		}

		wifi_connected_cur = ble_npl_time_get();
		wifi_connected_cur = ble_npl_time_ticks_to_ms32(wifi_connected_cur);
		iot_printf("ble smart cfg wifi_connected_start:%d timeout!:%d\n", wifi_connected_start, wifi_connected_cur);
		if ((wifi_connected_cur - wifi_connected_start) > 15000)  //wifi connect 15s timeout
		{
			iot_printf("ble smart cfg wifi_connected_start:%d timeout!:%d elapse:%d\n", wifi_connected_start, wifi_connected_cur, (wifi_connected_cur - wifi_connected_start));
			gatt_svr_chr_notify(ble_conn_handle, blesmt_notify_handle, wifi_conn_no, strlen(wifi_conn_no));
			ble_smart_info.step = 0;
			break;
		}
	*/
	}
#endif

	while (!ble_is_quit) 
	{
		sleep(1);
	}
	if(ble_status==ATBM_BLE_STATUS_ADVERTISE)
	{
		ble_gap_adv_stop();
		iot_printf("<====== ble_gap_adv_stop\n");
	}
	if(ble_status==ATBM_BLE_STATUS_CONNECT)
	{
		ble_gap_terminate(ble_conn_handle,BLE_ERR_REM_USER_CONN_TERM);
		sleep(2);
		iot_printf("<====== ble_gap_terminate(ble_conn_handle,19);\n");
	}
	smart_cfg_start = 0;
	ble_npl_sem_free(&hci_smt_sem);
	atbm_ThreadStopEvent(ble_smt_thread);
	iot_printf("<====== ble_smart_cfg_task end step %d\n", ble_smart_info.step);
	//sem_post(&sem_sock_sync);
	//strcpy(cmd_line,"quit");
	g_is_quit=1;
	smart_cfg_start = 0;
	return 0;
}

void ble_smart_cfg_startup(void)
{
	if(smart_cfg_start){
		iot_printf("ble smart cfg busy!\n");
		return;
	}
	iot_printf("[%s:%d] ble_smart_cfg_startup!11\n", __func__, __LINE__);
	memset(&ble_smart_info, 0, sizeof(struct ble_smart_cfg_t));
	ble_smt_thread = atbm_createThread(ble_smart_cfg_task, (atbm_void*)ATBM_NULL, BLE_APP_PRIO);
}

void ble_smart_cfg_stop(void)
{
	if(smart_cfg_start == 0){
		iot_printf("ble smart cfg not start!\n");
		return;
	}
	ble_smart_info.step = BLE_SMART_CFG_STATUS_STOP;
	ble_npl_sem_release(&hci_smt_sem);
}

#endif

typedef struct {
    UCHAR_T role;
    USHORT_T gatt_link;
    TKL_BLE_GAP_EVT_FUNC_CB gap_evt_cb;
    TKL_BLE_GATT_EVT_FUNC_CB gatt_evt_cb;
    TKL_BLE_GAP_ADDR_T local_addr;
    CHAR_T gap_name[32];
    // 可以添加更多的状态信息
} BLE_STATE_T;

static BLE_STATE_T g_ble_state;

/**
 * @brief   Function for initializing the ble stack
 * @param   role                Indicate the role for ble stack.
 *                              role = 1: ble peripheral    @TKL_BLE_ROLE_SERVER
 *                              role = 2: ble central       @TKL_BLE_ROLE_CLIENT
 * @return  SUCCESS             Initialized successfully.
 *          ERROR
 * */
OPERATE_RET tkl_ble_stack_init(UCHAR_T role)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_stack_init=================\n");
	// ble_smart_cfg_set_adv_name("cc051");
	// memcpy(device_name, "TY_test", strlen("TY_test"));
	// tuya_set_bt_device_name(device_name);
	// lib_ble_main_init("TUYA__test");
	// lib_ble_main_init("TY_test");
	// ble_hci_sync_init();
	// nimble_port_init();
	// ble_gatt_svcs_init();

	if (g_tlk_ble_gap_event_callback) {
		TKL_BLE_GAP_PARAMS_EVT_T gap_evt;
		memset(&gap_evt, 0, sizeof(TKL_BLE_GAP_PARAMS_EVT_T));
		
		gap_evt.type = TKL_BLE_EVT_STACK_INIT;
		gap_evt.result = 0;
		gap_evt.conn_handle = tuya_conn_handle;

		g_tlk_ble_gap_event_callback(&gap_evt);
	}
	memset(&g_ble_state, 0, sizeof(BLE_STATE_T));
	g_ble_state.role = role;
	printf("[%s:%d] role:%d \n", __func__, __LINE__, role);
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Function for de-initializing the ble stack features
 * @param   role                 Indicate the role for ble stack.
 *                               role = 1: ble peripheral
 *                               role = 2: ble central
 * @return  SUCCESS             Deinitialized successfully.
 *          ERROR
 * */
OPERATE_RET tkl_ble_stack_deinit(UCHAR_T role)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_stack_deinit=================\n");
	printf("[%s:%d] role:%d \n", __func__, __LINE__, role);
	if (role != g_ble_state.role) {
        return OPRT_INVALID_PARM;
    }
	memset(&g_ble_state, 0, sizeof(BLE_STATE_T));
	lib_ble_thread_exit();

	if (g_tlk_ble_gap_event_callback) {
		TKL_BLE_GAP_PARAMS_EVT_T gap_evt;
		memset(&gap_evt, 0, sizeof(TKL_BLE_GAP_PARAMS_EVT_T));

		gap_evt.type = TKL_BLE_EVT_STACK_DEINIT;
		gap_evt.result = 0;

		g_tlk_ble_gap_event_callback(&gap_evt);
	}
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Function for getting the GATT Link-Support.
 * @param   p_link              return gatt link                 
 * @return  SUCCESS             Support Gatt Link
 *          ERROR               Only Beacon or Mesh Beacon, Not Support Gatt Link.
 * */
OPERATE_RET tkl_ble_stack_gatt_link(USHORT_T *p_link)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_stack_gatt_link=================\n");
	*p_link = g_gatt_link;
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Register GAP Event Callback
 * @param   TKL_BLE_GAP_EVT_FUNC_CB Refer to @TKL_BLE_GAP_EVT_FUNC_CB
 * @return  SUCCESS         Register successfully.
 *          ERROR
 * */
OPERATE_RET tkl_ble_gap_callback_register(CONST TKL_BLE_GAP_EVT_FUNC_CB gap_evt)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_gap_callback_register=================\n");
	g_tlk_ble_gap_event_callback = gap_evt;

	
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Register GATT Event Callback
 * @param   TKL_BLE_GATT_EVT_FUNC_CB Refer to @TKL_BLE_GATT_EVT_FUNC_CB
 * @return  SUCCESS         Register successfully.
 *          ERROR
 * */
OPERATE_RET tkl_ble_gatt_callback_register(CONST TKL_BLE_GATT_EVT_FUNC_CB gatt_evt)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_gatt_callback_register=================\n");
	g_tlk_ble_gatt_event_callback = gatt_evt;
	
    return OPRT_OK;
    // --- END: user implements ---
}

/******************************************************************************************************************************/
/** @brief Define All GAP Interface
 */
/**
 * @brief   Set the local Bluetooth identity address.
 *          The local Bluetooth identity address is the address that identifies this device to other peers.
 *          The address type must be either @ref TKL_BLE_GAP_ADDR_TYPE_PUBLIC or @ref TKL_BLE_GAP_ADDR_TYPE_RANDOM.
 * @param   [in] p_peer_addr:   pointer to local address parameters 
 * @return  SUCCESS
 *          ERROR
 * */ 
OPERATE_RET tkl_ble_gap_addr_set(TKL_BLE_GAP_ADDR_T CONST *p_peer_addr)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_gap_addr_set=================\n");
	printf("[%s:%d] p_peer_addr:%s \n", __func__, __LINE__, p_peer_addr);
	if (p_peer_addr == NULL) {
        return OPRT_INVALID_PARM;
    }
	
	memcpy(&g_local_addr, p_peer_addr, sizeof(TKL_BLE_GAP_ADDR_T));
	
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Get the local Bluetooth identity address.
 * @param   [out] p_peer_addr:  pointer to local address
 * @return  SUCCESS             Set Address successfully.
 *          ERROR
 * */
OPERATE_RET tkl_ble_gap_address_get(TKL_BLE_GAP_ADDR_T *p_peer_addr)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_gap_address_get=================\n");
	
	if (p_peer_addr == NULL) {
        return OPRT_INVALID_PARM;
    }
    memcpy(p_peer_addr, &g_local_addr, sizeof(TKL_BLE_GAP_ADDR_T));
	printf("[%s:%d] p_peer_addr:%s \n", __func__, __LINE__, p_peer_addr);
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Start advertising
 * @param   [in] p_adv_params : pointer to advertising parameters 
 * @return  SUCCESS
 *  ERROR
 * */ 
OPERATE_RET tkl_ble_gap_adv_start(TKL_BLE_GAP_ADV_PARAMS_T CONST *p_adv_params)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_gap_adv_start=================\n");
	
	if (p_adv_params == NULL) {
		printf("[%s:%d] Error, p_adv_params is null \n", __func__, __LINE__);
        return OPRT_INVALID_PARM;
    }
	struct ble_gap_adv_params adv_params;
	// adv_params.itvl_max = p_adv_params->adv_interval_max;
	// adv_params.itvl_min = p_adv_params->adv_interval_min;

	ble_smart_set_adv_params(&adv_params);
	ble_smart_reg_gap_event_proc(ble_gap_event);

	lib_ble_main_init("TY_test");
	if (g_st_gap_adv_data && g_st_gap_adv_rsp_data) {
		ble_gap_adv_set_data(g_st_gap_adv_data, g_st_gap_adv_data_len);
		ble_gap_adv_rsp_set_data(g_st_gap_adv_rsp_data, g_st_gap_adv_rsp_data_len);
	}

	// memcpy(&g_tkl_ble_gatt_adv_param, p_adv_params, sizeof(TKL_BLE_GAP_ADV_PARAMS_T));

	// ble_smart_cfg_startup();
#if 0
    struct ble_gap_adv_params adv_params;
	int rc;
	printf("[%s:%d] p_adv_params->adv_interval_min:%d \n", __func__, __LINE__, p_adv_params->adv_interval_min);
	printf("[%s:%d] p_adv_params->adv_interval_max:%d \n", __func__, __LINE__, p_adv_params->adv_interval_max);
	printf("[%s:%d] p_adv_params->adv_channel_map:%d \n", __func__, __LINE__, p_adv_params->adv_channel_map);
	printf("[%s:%d] p_adv_params->direct_addr.type:%d \n", __func__, __LINE__, p_adv_params->direct_addr.type);
    memset(&adv_params, 0, sizeof(adv_params));
    adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
    adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
	// adv_params.itvl_min = p_adv_params->adv_interval_min;
	// adv_params.itvl_max = p_adv_params->adv_interval_max;
	adv_params.channel_map = p_adv_params->adv_channel_map;

	if(p_adv_params->direct_addr.type == TKL_BLE_GAP_ADDR_TYPE_PUBLIC)
		blesmt_addr_type = BLE_OWN_ADDR_PUBLIC;
	else if(p_adv_params->direct_addr.type == TKL_BLE_GAP_ADDR_TYPE_RANDOM)
		blesmt_addr_type = BLE_OWN_ADDR_RANDOM;
		
    rc = ble_gap_adv_start(blesmt_addr_type, NULL, BLE_HS_FOREVER,
                           		&adv_params, ble_slave_gap_event, NULL);
	if(!rc)
		ble_status=ATBM_BLE_STATUS_ADVERTISE;
    if (rc != 0) {
        printf("[%s:%d] error enabling advertisement; rc=%d\n", __func__, __LINE__, rc);
		if (rc == BLE_HS_EALREADY) {
			return OPRT_OK;
		}
        return OPRT_COM_ERROR;
    }
#endif	
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Stop advertising
 * @param   VOID
 * @return  SUCCESS
 *          ERROR
 * */ 
OPERATE_RET tkl_ble_gap_adv_stop(VOID)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_gap_adv_stop=================\n");
	// ble_gap_adv_stop();
	// lib_ble_thread_exit();
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Setting advertising data
 * @param   [in] p_adv:         Data to be used in advertisement packets, and include adv data len
 *          [in] p_scan_rsp:    Data to be used in advertisement respond packets, and include rsp data len
 * @Note    Please Check p_adv and p_scan_rsp, if data->p_data == NULL or data->length == 0, we will not update these values.
 * @return  SUCCESS
 *          ERROR
 * */ 
OPERATE_RET tkl_ble_gap_adv_rsp_data_set(TKL_BLE_DATA_T CONST *p_adv, TKL_BLE_DATA_T CONST *p_scan_rsp)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_gap_adv_rsp_data_set=================\n");
	
	
	if ((p_adv != NULL && (p_adv->p_data == NULL || p_adv->length == 0)) ||
        (p_scan_rsp != NULL && (p_scan_rsp->p_data == NULL || p_scan_rsp->length == 0))) {
        return OPRT_INVALID_PARM;
    }
	printf("[%s:%d] ", __func__, __LINE__);
	for (int i = 0 ; i < p_adv->length ; i ++) {
		printf("%#x ", p_adv->p_data[i]);
	}
	printf("\n");
	int ret = 0;
	// int ret = ble_gap_adv_set_data(p_adv->p_data, p_adv->length);
	
	for (int i = 0 ; i < 10 ; i++) {
		ret = ble_gap_adv_set_data(p_adv->p_data, p_adv->length);
		if (ret == 0) {
			break;
		}
		printf("[%s:%d] ble_gap_adv_set_data failed, ret:%#x \n", __func__, __LINE__, ret);
	}

	for (int i = 0 ; i < 10 ; i++) {
		ret = ble_gap_adv_rsp_set_data(p_scan_rsp->p_data, p_scan_rsp->length);
		if (ret == 0) {
			break;
		}
		printf("[%s:%d] ble_gap_adv_rsp_set_data failed, ret:%#x \n", __func__, __LINE__, ret);
	}
	
	

	if (g_st_gap_adv_data && p_adv->length != g_st_gap_adv_data_len) {
		free(g_st_gap_adv_data);
		g_st_gap_adv_data = NULL;
		g_st_gap_adv_data_len = 0;
	}
	if (g_st_gap_adv_rsp_data && p_scan_rsp->length != g_st_gap_adv_rsp_data_len) {
		free(g_st_gap_adv_rsp_data);
		g_st_gap_adv_rsp_data = NULL;
		g_st_gap_adv_rsp_data_len = 0;
	}

	if (!g_st_gap_adv_data) {
		g_st_gap_adv_data = (UCHAR_T*) malloc(p_adv->length);
		if (!g_st_gap_adv_data) {
			return OPRT_MALLOC_FAILED;
		}
		g_st_gap_adv_data_len = p_adv->length;
	}

	if (!g_st_gap_adv_rsp_data) {
		g_st_gap_adv_rsp_data = (UCHAR_T*) malloc(p_scan_rsp->length);
		if (!g_st_gap_adv_rsp_data) {
			return OPRT_MALLOC_FAILED;
		}
		g_st_gap_adv_rsp_data_len = p_scan_rsp->length;
	}

	memcpy(g_st_gap_adv_data, p_adv->p_data, p_adv->length);
	memcpy(g_st_gap_adv_rsp_data, p_scan_rsp->p_data, p_scan_rsp->length);
	return OPRT_OK;
#if 0
    struct ble_hs_adv_fields fields;
	ble_uuid16_t uuids16[2];
	uint8_t mfg_data[3] = {0xAB, 0xAB, 0xA0};
	int rc;

    memset(&fields, 0, sizeof(fields));	
	
    fields.name = (uint8_t *)device_name;
    fields.name_len = strlen(device_name);
    fields.name_is_complete = 1;

	uuids16[0].u.type = BLE_UUID_TYPE_16;
	uuids16[0].value = BLE_ATBM_GAP_SVR;
	uuids16[1].u.type = BLE_UUID_TYPE_16;
	uuids16[1].value = BLE_ATBM_GAP_SVR1;
	fields.uuids16 = &uuids16[0];
	fields.num_uuids16 = 2;
	fields.uuids16_is_complete = 1;

	fields.mfg_data = p_adv->p_data;
	fields.mfg_data_len = p_adv->length;
	
    rc = ble_gap_adv_set_fields(&fields);
    if (rc != 0) {
        iot_printf("[%s:%d] error setting advertisement data; rc=%d\n", __func__, __LINE__, rc);
        return;
    }
	
	struct ble_hs_adv_fields adv_fields;
	ble_uuid16_t uuids16_rsp[2];
	uint8_t mfg_rsp_data[3] = {0xff, 0xcc, 0xdd};
	memset(&adv_fields, 0, sizeof(adv_fields));	

	adv_fields.name = (uint8_t *)device_name;
	adv_fields.name_len = strlen(device_name);
	adv_fields.name_is_complete = 1;

	uuids16_rsp[0].u.type = BLE_UUID_TYPE_16;
	uuids16_rsp[0].value = 0xccc0;
	uuids16_rsp[1].u.type = BLE_UUID_TYPE_16;
	uuids16_rsp[1].value = 0xddd0;
	adv_fields.uuids16 = &uuids16_rsp[0];
	adv_fields.num_uuids16 = 2;
	adv_fields.uuids16_is_complete = 1;
	adv_fields.mfg_data = p_scan_rsp->p_data;
	adv_fields.mfg_data_len = p_scan_rsp->length;
	rc=ble_gap_adv_rsp_set_fields(&adv_fields);
	 if (rc != 0) {
	    iot_printf("[%s:%d] error setting advertisement data; rc=%d\n", __func__, __LINE__, rc);
	    return;
	}
	 
    return OPRT_OK;
#endif
    // --- END: user implements ---
}

/**
 * @brief   Update advertising data
 * @param   [in] p_adv: Data    to be used in advertisement packets, and include adv data len
 *          [in] p_scan_rsp:    Data to be used in advertisement respond packets, and include rsp data len
 * @Note    Please Check p_adv and p_scan_rsp, if data->p_data == NULL or data->length == 0, we will not update these values.
 * @return  SUCCESS
 *          ERROR
 * */ 
OPERATE_RET tkl_ble_gap_adv_rsp_data_update(TKL_BLE_DATA_T CONST *p_adv, TKL_BLE_DATA_T CONST *p_scan_rsp)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_gap_adv_rsp_data_update=================\n");

    return tkl_ble_gap_adv_rsp_data_set(p_adv, p_scan_rsp);;
    // --- END: user implements ---
}

/**
 * @brief   Start scanning
 * @param   [in] scan_param:    scan parameters including interval, windows
 * @return  SUCCESS
 *          ERROR
 * */ 
OPERATE_RET tkl_ble_gap_scan_start(TKL_BLE_GAP_SCAN_PARAMS_T CONST *p_scan_params)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_gap_scan_start=================\n");
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Stop scanning
 * @param   VOID
 * @return  SUCCESS
 *          ERROR
 * */ 
OPERATE_RET tkl_ble_gap_scan_stop(VOID)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_gap_scan_stop=================\n");
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Start connecting one peer
 * @param   [in] p_peer_addr:   include address and address type
 *          [in] p_scan_params: scan parameters
 *          [in] p_conn_params: connection  parameters
 * @return  SUCCESS
 *          ERROR
 * */ 
OPERATE_RET tkl_ble_gap_connect(TKL_BLE_GAP_ADDR_T CONST *p_peer_addr, TKL_BLE_GAP_SCAN_PARAMS_T CONST *p_scan_params, TKL_BLE_GAP_CONN_PARAMS_T CONST *p_conn_params)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_gap_connect=================\n");
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Disconnect from peer
 * @param   [in] conn_handle:   the connection handle
 *          [in] hci_reason:    terminate reason
 * @return  SUCCESS
 *          ERROR
 * */ 
OPERATE_RET tkl_ble_gap_disconnect(USHORT_T conn_handle, UCHAR_T hci_reason)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_gap_disconnect=================\n");
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Start to update connection parameters
 * @param   [in] conn_handle:   connection handle
 *          [in] p_conn_params: connection  parameters
 * @return  SUCCESS
 *          ERROR
 * */
OPERATE_RET tkl_ble_gap_conn_param_update(USHORT_T conn_handle, TKL_BLE_GAP_CONN_PARAMS_T CONST *p_conn_params)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_gap_conn_param_update=================\n");
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Set the radio's transmit power.
 * @param   [in] role:          0: Advertising Tx Power; 1: Scan Tx Power; 2: Connection Power
 *          [in] tx_power:      tx power:This value will be magnified 10 times. 
 *                              If the tx_power value is -75, the real power is -7.5dB.(or 40 = 4dB)
 * @return  SUCCESS
 *          ERROR
 * */ 
OPERATE_RET tkl_ble_gap_tx_power_set(UCHAR_T role, INT_T tx_power)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_gap_tx_power_set=================\n");
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Get the received signal strength for the last connection event.
 * @param   [in]conn_handle:    connection handle
 * @return  SUCCESS             Successfully read the RSSI.
 *          ERROR               No sample is available.
 * */
OPERATE_RET tkl_ble_gap_rssi_get(USHORT_T conn_handle)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_gap_rssi_get=================\n");
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Set the GAP Name For Bluetooth
 * @param   [in]p_name:         GAP Name String
 * @return  SUCCESS
 *          ERROR
 * */
OPERATE_RET tkl_ble_gap_name_set(CHAR_T *p_name)
{
    // --- BEGIN: user implements ---
	printf("==================tkl_ble_gap_name_set=========p_name:%s========\n", p_name);

	// strncpy(device_name, p_name, sizeof(device_name));
	// ble_svc_gap_device_name_set(p_name);

    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Add Ble Gatt Service
 * @param   [in] p_service: define the ble service
 *
 * @return  SUCCESS
 *          ERROR
 * */ 
OPERATE_RET tkl_ble_gatts_service_add(TKL_BLE_GATTS_PARAMS_T *p_service)
{
    // --- BEGIN: user implements ---	
	printf("==================tkl_ble_gatts_service_add=================\n");
	printf("[%s:%d] p_service->svc_num:%#x \n", __func__, __LINE__, p_service->svc_num);
	printf("[%s:%d] p_service->p_service->handle:%#x \n", __func__, __LINE__, p_service->p_service->handle);
	printf("[%s:%d] p_service->p_service->svc_uuid:%#x \n", __func__, __LINE__, p_service->p_service->svc_uuid);
	printf("[%s:%d] p_service->p_service->type:%#x \n", __func__, __LINE__, p_service->p_service->type);
	printf("[%s:%d] p_service->p_service->char_num:%#x \n", __func__, __LINE__, p_service->p_service->char_num);
    // int rc = ble_gatts_add_svcs(gatt_svr_svcs);
	// ble_smart_gatt_svcs_init();
    UINT8_T svc_num             = 0;
    struct ble_gatt_svc_def *gatt_svc = NULL;

    svc_num = p_service->svc_num;
    printf("register gatt service, num: %d\r\n",svc_num);
	for (int i = 0; i < svc_num; i++) {
		TKL_BLE_SERVICE_PARAMS_T *p_service_param = &p_service->p_service[i];
		printf("[%s:%d] i=%d,  p_service_param->svc_uuid.uuid_type:%#x \n", __func__, __LINE__, i, p_service_param->svc_uuid.uuid_type);
		printf("[%s:%d] i=%d,  p_service_param->handle:%#x \n", __func__, __LINE__, i, p_service_param->handle);
		printf("[%s:%d] i=%d,  p_service_param->type:%#x \n", __func__, __LINE__, i, p_service_param->type);
		printf("[%s:%d] i=%d,  p_service_param->svc_uuid.uuid.uuid16:%#x \n", __func__, __LINE__, i, p_service_param->svc_uuid.uuid.uuid16);
		printf("[%s:%d] i=%d,  p_service_param->char_num:%#x \n", __func__, __LINE__, i, p_service_param->char_num);
		for (int j = 0; j < p_service_param->char_num; j++) {
			printf("[%s:%d] i=%d,  p_service_param->p_char[%d].char_uuid.uuid_type:%#x \n", __func__, __LINE__, i, j, p_service_param->p_char[j].char_uuid.uuid_type);
			printf("[%s:%d] i=%d,  p_service_param->p_char[%d].char_uuid.uuid128:%#x \n", __func__, __LINE__, i, j, p_service_param->p_char[j].char_uuid.uuid.uuid128);
			printf("[%s:%d] i=%d,  p_service_param->p_char[%d].handle:%#x \n", __func__, __LINE__, i, j, p_service_param->p_char[j].handle);
			printf("[%s:%d] i=%d,  p_service_param->p_char[%d].permission:%#x \n", __func__, __LINE__, i, j, p_service_param->p_char[j].permission);
			printf("[%s:%d] i=%d,  p_service_param->p_char[%d].property:%#x \n", __func__, __LINE__, i, j, p_service_param->p_char[j].property);
			printf("[%s:%d] i=%d,  p_service_param->p_char[%d].value_len:%#x \n", __func__, __LINE__, i, j, p_service_param->p_char[j].value_len);
		}
		
	}
#if 1
    gatt_svc = (struct ble_gatt_svc_def *)malloc(svc_num * sizeof(struct ble_gatt_svc_def));
    if (!gatt_svc) {
        return OPRT_MALLOC_FAILED;
    }
    memset(gatt_svc, 0, svc_num * sizeof(struct ble_gatt_svc_def));
	

    for (int i = 0; i < svc_num; i++) {
        /* Service Information */
        TKL_BLE_SERVICE_PARAMS_T *p_service_param = &p_service->p_service[i];
		ble_uuid16_t *uuid = (ble_uuid16_t*)malloc(svc_num * sizeof(ble_uuid16_t));
		gatt_svc[i].uuid = (ble_uuid_t*)uuid;
		uuid->value = p_service_param->svc_uuid.uuid.uuid16;
		uuid->u.type = BLE_UUID_TYPE_16;
		printf("[%s:%d] i=%d,  p_service_param->type:%#x \n", __func__, __LINE__, i, p_service_param->type);
		ble_gatt_access_fn *access_cb;
		if (p_service_param->type == TKL_BLE_UUID_UNKNOWN) {
			gatt_svc[i].type = BLE_GATT_SVC_TYPE_END;
			// access_cb = ble_svc_dis_access;
		} else if (p_service_param->type == TKL_BLE_UUID_SERVICE_PRIMARY) {
			gatt_svc[i].type = BLE_GATT_SVC_TYPE_PRIMARY;
		} else if (p_service_param->type == TKL_BLE_UUID_SERVICE_SECONDARY){
			gatt_svc[i].type = BLE_GATT_SVC_TYPE_SECONDARY;
		} else if (p_service_param->type == TKL_BLE_UUID_SERVICE_INCLUDE){
			gatt_svc[i].type = BLE_GATT_SVC_TYPE_PRIMARY;
		} else if (p_service_param->type == TKL_BLE_UUID_CHARACTERISTIC){
			gatt_svc[i].type = BLE_GATT_SVC_TYPE_PRIMARY;
		}

        p_service_param->handle = p_service_param->svc_uuid.uuid.uuid16;

        tuya_conn_handle = p_service_param->handle;
        printf("--- tuya_conn_handle :%04x\n", tuya_conn_handle);

        /* Characteristic information*/
        UINT8_T chr_num                    = p_service_param->char_num;
        struct ble_gatt_chr_def *gatt_chr = (struct ble_gatt_chr_def *)malloc(chr_num * SIZEOF(struct ble_gatt_chr_def));
        if (!gatt_chr) {
            free(gatt_svc);
            return OPRT_MALLOC_FAILED;
        }
        memset(gatt_chr, 0, chr_num * SIZEOF(struct ble_gatt_chr_def));

        for (int j = 0; j < chr_num; j++) {
			if (p_service_param->p_char[j].char_uuid.uuid_type == TKL_BLE_UUID_TYPE_16) {
				ble_uuid16_t* uuid16 = (ble_uuid16_t*)malloc(sizeof(ble_uuid16_t));
				gatt_chr[j].uuid = (ble_uuid_t*)uuid16;
				uuid16->u.type = BLE_UUID_TYPE_16;
				memcpy(uuid16->value, p_service_param->p_char[j].char_uuid.uuid.uuid16, sizeof(uuid16->value));
			} else if (p_service_param->p_char[j].char_uuid.uuid_type == TKL_BLE_UUID_TYPE_32) {
				ble_uuid32_t* uuid32 = (ble_uuid32_t*)malloc(sizeof(ble_uuid32_t));
				gatt_chr[j].uuid = (ble_uuid_t*)uuid32;
				uuid32->u.type = BLE_UUID_TYPE_32;
				memcpy(uuid32->value, p_service_param->p_char[j].char_uuid.uuid.uuid32, sizeof(uuid32->value));
			} else if (p_service_param->p_char[j].char_uuid.uuid_type == TKL_BLE_UUID_TYPE_128) {
				ble_uuid128_t* uuid128 = (ble_uuid128_t*)malloc(sizeof(ble_uuid128_t));
				gatt_chr[j].uuid = (ble_uuid_t*)uuid128;
				uuid128->u.type = BLE_UUID_TYPE_128;
				memcpy(uuid128->value, p_service_param->p_char[j].char_uuid.uuid.uuid128, sizeof(uuid128->value));
			}

            gatt_chr[j].flags = p_service_param->p_char[j].property;
			gatt_chr[j].access_cb = ble_svc_gatt_access;

            /**
             * FIXME: BlueZ does not focus on the handle, so in this
             *        case, we're using the uuid as
             *        the handle value to differentiate the specific
             *        characteristic.
             */
			char str_uuid_buf[128] = {0};
			if (ble_uuid_to_str(gatt_chr[j].uuid, str_uuid_buf)) {
				printf("str_uuid_buf:%s \n", str_uuid_buf);
				p_service_param->p_char[j].handle = atoi(str_uuid_buf);
			} else {
				p_service_param->p_char[j].handle = ble_uuid_u16(gatt_chr[j].uuid);
			}
            
            printf("p_service_param->p_char[%d].handle:%d\r\n", j, p_service_param->p_char[j].handle);
        }

        gatt_svc[i].characteristics = gatt_chr;
    }

    ble_smart_add_gatt_svcs(gatt_svc, svc_num);

#endif
    // for (i = 0; i < svc_num; i++) {
    //     if (gatt_svc[i].chr) {
    //         free(gatt_svc[i].chr);
    //     }
    // }
    // free(gatt_svc);
    return OPRT_OK;
    // --- END: user implements ---
}

OPERATE_RET tkl_ble_gatts_service_change(USHORT_T conn_handle, USHORT_T start_handle, USHORT_T end_handle)
{
    // --- BEGIN: user implements ---
    return OPRT_NOT_SUPPORTED;
    // --- END: user implements ---    
}
/**
 * @brief   Set the value of a given attribute. After Config Tuya Read-Char, we can update read-value at any time.
 * @param   [in] conn_handle    Connection handle.
 *          [in] char_handle    Attribute handle.
 *          [in,out] p_value    Attribute value information.
 * @return  SUCCESS
 *          ERROR
 *
 * @note Values other than system attributes can be set at any time, regardless of whether any active connections exist. 
 * */ 
OPERATE_RET tkl_ble_gatts_value_set(USHORT_T conn_handle, USHORT_T char_handle, UCHAR_T *p_data, USHORT_T length)
{
    // --- BEGIN: user implements ---
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Get the value of a given attribute.
 * @param   [in] conn_handle    Connection handle. Ignored if the value does not belong to a system attribute.
 * @param   [in] char_handle    Attribute handle.
 * @return  SUCCESS
 *          ERROR
 * */ 
OPERATE_RET tkl_ble_gatts_value_get(USHORT_T conn_handle, USHORT_T char_handle, UCHAR_T *p_data, USHORT_T length)
{
    // --- BEGIN: user implements ---
    return OPRT_NOT_SUPPORTED;
    // --- END: user implements ---
}

/**
 * @brief   Notify an attribute value.
 * @param   [in] conn_handle    Connection handle.
 * @param   [in] char_handle    Attribute handle.
 *          [in] p_data         Notify Values
 *          [in] length         Value Length
 * @return  SUCCESS
 *          ERROR
 * */ 
OPERATE_RET tkl_ble_gatts_value_notify(USHORT_T conn_handle, USHORT_T char_handle, UCHAR_T *p_data, USHORT_T length)
{
    // --- BEGIN: user implements ---
	printf("[%s:%d] ============tkl_ble_gatts_value_notify============\n", __func__, __LINE__);
	printf("[%s:%d] p_data:", __func__, __LINE__);
	for(int i = 0; i < length ; i ++) {
		printf("0x%x ", p_data[i]);
	}
	printf("\n");
	gatt_svr_chr_notify(conn_handle, char_handle, p_data, length);

    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Indicate an attribute value.
 * @param   [in] conn_handle    Connection handle.
 * @param   [in] char_handle    Attribute handle.
 *          [in] p_data         Notify Values
 *          [in] length         Value Length
 * @return  SUCCESS
 *          ERROR
 * */ 
OPERATE_RET tkl_ble_gatts_value_indicate(USHORT_T conn_handle, USHORT_T char_handle, UCHAR_T *p_data, USHORT_T length)
{
    // --- BEGIN: user implements ---
    int rc, cnt=0;
	printf("[%s:%d] p_data:", __func__, __LINE__);
	while((rc != 0) && (cnt < 5)) {
		cnt ++;
		for(int i = 0; i < length ; i ++) {
			printf("0x%x ", p_data[i]);
		}
		printf("\n");
		rc = gatt_svr_chr_indicate(conn_handle, char_handle, (char *)p_data, length);
	}
	
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   Reply to an ATT_MTU exchange request by sending an Exchange MTU Response to the client.
 * @param   [in] conn_handle    Connection handle.
 *          [in] server_rx_mtu  mtu size.
 * @return  SUCCESS
 *          ERROR
 * */ 
OPERATE_RET tkl_ble_gatts_exchange_mtu_reply(USHORT_T conn_handle, USHORT_T server_rx_mtu)
{
    // --- BEGIN: user implements ---
    return OPRT_NOT_SUPPORTED;
    // --- END: user implements ---
}

/******************************************************************************************************************************/
/** @brief Define All Gatt Client Interface, Refer to current ble gw and ble stack.
 *
 *  Notes: notice the handle will be the one of signed point.
 *  Discovery Operations belongs to GAP Interface, But declear here, because it will be used for the gatt client.
 */
 
/**
 * @brief   [Ble Central] Will Discovery All Service
 * @param   [in] conn_handle    Connection handle.
 * @return  SUCCESS
 *          ERROR
 * */ 
OPERATE_RET tkl_ble_gattc_all_service_discovery(USHORT_T conn_handle)
{
    // --- BEGIN: user implements ---
    return 0;
    // --- END: user implements ---
}

/**
 * @brief   [Ble Central] Will Discovery All Characteristic
 * @param   [in] conn_handle    Connection handle.
 *          [in] start_handle   Handle of start
 *          [in] end_handle     Handle of End
 * @return  SUCCESS
 *          ERROR
 * @Note:   For Tuya Service, it may contains more optional service, it is more better to find all Characteristic 
 *          instead of find specific uuid.
 * */  
OPERATE_RET tkl_ble_gattc_all_char_discovery(USHORT_T conn_handle, USHORT_T start_handle, USHORT_T end_handle)
{
    // --- BEGIN: user implements ---
    return OPRT_NOT_SUPPORTED;
    // --- END: user implements ---
}

/**
 * @brief   [Ble Central] Will Discovery All Descriptor of Characteristic
 * @param   [in] conn_handle    Connection handle.
 * @param   [in] conn_handle    Connection handle.
 *          [in] start_handle   Handle of start
 *          [in] end_handle     Handle of End
 * @return  SUCCESS
 *          ERROR
 * */ 
OPERATE_RET tkl_ble_gattc_char_desc_discovery(USHORT_T conn_handle, USHORT_T start_handle, USHORT_T end_handle)
{
    // --- BEGIN: user implements ---
    return OPRT_NOT_SUPPORTED;
    // --- END: user implements ---
}

/**
 * @brief   [Ble Central] Write Data without Response
 * @param   [in] conn_handle    Connection handle.
 * @param   [in] char_handle    Attribute handle.
 *          [in] p_data         Write Values
 *          [in] length         Value Length
 * @return  SUCCESS
 *          ERROR
 * */ 
OPERATE_RET tkl_ble_gattc_write_without_rsp(USHORT_T conn_handle, USHORT_T char_handle, UCHAR_T *p_data, USHORT_T length)
{
    // --- BEGIN: user implements ---
    return OPRT_NOT_SUPPORTED;
    // --- END: user implements ---
}

/**
 * @brief   [Ble Central] Write Data with response
 * @param   [in] conn_handle    Connection handle.
 * @param   [in] char_handle    Attribute handle.
 *          [in] p_data         Write Values
 *          [in] length         Value Length
 * @return  SUCCESS
 *          ERROR
 * */
OPERATE_RET tkl_ble_gattc_write(USHORT_T conn_handle, USHORT_T char_handle, UCHAR_T *p_data, USHORT_T length)
{
    // --- BEGIN: user implements ---
    return OPRT_NOT_SUPPORTED;
    // --- END: user implements ---
}

/**
 * @brief   [Ble Central] Read Data
 * @param   [in] conn_handle    Connection handle.
 * @param   [in] char_handle    Attribute handle.
 * @return  SUCCESS
 *          ERROR
 * */
OPERATE_RET tkl_ble_gattc_read(USHORT_T conn_handle, USHORT_T char_handle)
{
    // --- BEGIN: user implements ---
    return OPRT_NOT_SUPPORTED;
    // --- END: user implements ---
}

/**
 * @brief   Start an ATT_MTU exchange by sending an Exchange MTU Request to the server.
 * @param   [in] conn_handle    Connection handle.
 *          [in] client_rx_mtu  mtu size.
 * @return  SUCCESS
 *          ERROR
 * */
OPERATE_RET tkl_ble_gattc_exchange_mtu_request(USHORT_T conn_handle, USHORT_T client_rx_mtu)
{
    // --- BEGIN: user implements ---
	printf("[%s:%d] client_rx_mtu:%d \n", __func__, __LINE__, client_rx_mtu);
	ble_att_set_preferred_mtu(client_rx_mtu);
	ble_gattc_exchange_mtu(conn_handle, NULL, NULL);
    return OPRT_OK;
    // --- END: user implements ---
}

/**
 * @brief   [Special Command Control] Base on Bluetooth, We can do some special commands for exchanging some informations.
 * @param   [in] opcode         Operations Opcode.
 *          [in] user_data      Post Some Special Commands Data.
 *          [in] data_len       User's Data Length.
 * @note    For Operations Codes, we can do anythings after exchange from TAL Application
 *          And We define some Opcodes as below for reference.
 *          For Bluetooth NCP Module: Mask=0x01, Code ID: 0x00~0xff. Opcode = ((0x01 << 8) & Code ID)
 *          eg:     0x0100: Special Vendor Module Init
 *                  0x0101: Special Vendor Module Deinit
 *                  0x0102: Special Vendor Module Reset
 *                  0x0103: Special Vendor Module Check Exist: Return OPRT_OK or OPRT_NOT_FOUND ..
 *                  0x0104: Specail Vendor Module Version Get.
 *                  0x0105: Specail Vendor Module Version Set.
 *                  0x0106: Specail Vendor Module Version Update.
 *                  0x0107: Specail Vendor Module Scan Switch.
 *                  0x0108: Specail Vendor Module Scan Stop.
 *                  0x0109: Specail Vendor Module Auth Check.
 *                  0x0110: Specail Vendor Module Auth Erase.
 *
 *  * @return  SUCCESS
 *          ERROR
 * */
OPERATE_RET tkl_ble_vendor_command_control(USHORT_T opcode, VOID_T *user_data, USHORT_T data_len)
{
    // --- BEGIN: user implements ---
    return OPRT_NOT_SUPPORTED;
    // --- END: user implements ---
}

OPERATE_RET tkl_ble_set_mode(CONST BOOL_T enable, CONST UCHAR_T mode)
{
    // --- BEGIN: user implements ---
    return OPRT_NOT_SUPPORTED;
    // --- END: user implements ---    
}
