#include "include.h"
#include "wireless_service.h"
#include "ble_client.h"

///////////////////////////////////////////////////////////////////////////
#define MAX_TX_NUM          8
#define MAX_TX_LEN          128
#define TX_POOL_SIZE        (MAX_TX_LEN + sizeof(struct txbuf_tag)) * MAX_TX_NUM


ble_cb_t ble_cb AT(.ble_buf.var);

AT(.ble_cache.att)
uint8_t ble_tx_pool[TX_POOL_SIZE];

#if LE_DUT_UART_EN
BT_WORK_MODE cfg_bt_work_mode            = MODE_NORMAL;

void ble_set_work_mode(BT_WORK_MODE mode)
{
    cfg_bt_work_mode = mode;
}


BT_WORK_MODE ble_get_work_mode(void)
{
    return cfg_bt_work_mode;
}
#endif // LE_DUT_UART_EN

void ble_txpkt_init(void)
{
    memset(&ble_tx, 0x00, sizeof(ble_tx));

    txpkt_init(&ble_tx, ble_tx_pool, MAX_TX_NUM, MAX_TX_LEN);
    ble_tx.send_kick = ble_send_kick;
}

void ble_sm_param_init(void)
{
    uint8_t security_req_en = 0;
    uint8_t auth_req = SM_AUTHREQ_BONDING | SM_AUTHREQ_MITM_PROTECTION;
    uint8_t io_capability = IO_CAPABILITY_NO_INPUT_NO_OUTPUT;

    ble_sm_init(security_req_en, io_capability, auth_req);
}

void ble_adv_param_init(bool adv_en)
{
    adv_param_t adv_info;

    memset(&adv_info,0,sizeof(adv_info));
    adv_info.adv_len = ble_get_adv_data(adv_info.adv_data, sizeof(adv_info.adv_data));
    adv_info.scan_rsp_len = ble_get_scan_data(adv_info.scan_rsp, sizeof(adv_info.scan_rsp));
    adv_info.adv_int_min = adv_info.adv_int_max = 0x30;
    adv_info.adv_type = ADV_TYPE_IND;
    adv_info.adv_en = adv_en;
    adv_info.channel_map = 0x07;

    ble_set_adv_param(&adv_info);
}

void ble_dir_adv_param_init(bool adv_en)
{
    sm_bonding_info_t bind_info;

    adv_param_t adv_info;
    memset(&adv_info,0,sizeof(adv_info));
    adv_info.adv_len = ble_get_adv_data(adv_info.adv_data, sizeof(adv_info.adv_data));
    adv_info.scan_rsp_len = ble_get_scan_data(adv_info.scan_rsp, sizeof(adv_info.scan_rsp));
    adv_info.adv_int_min = adv_info.adv_int_max = 0x30;
    adv_info.adv_type = ADV_TYPE_DIRECT_LO_IND;
    adv_info.adv_en = adv_en;
	adv_info.channel_map = 0x07;
    adv_info.filter_policy = 3;

    if (bsp_ble_bind_state(0, &bind_info)) {
        uint8_t addr[7];
        param_ble_central_addr_read(addr);
        printf("dir adv addr type = %x, addr:", addr[0]);
        print_r(&addr[1], 6);

        adv_info.direct_address_typ = addr[0];

        for (uint8_t i = 0; i < 6; i++) {
            adv_info.direct_address[i] = addr[6 - i];
        }
    }

    ble_set_adv_param(&adv_info);
}

void ble_rpa_param_init(void)
{
    rpa_param_t rpa_info;

    memset(&rpa_info, 0, sizeof(rpa_param_t));

    rpa_info.rpa_en = 1;
    rpa_info.renew_to = 600;

    ble_set_rslv_renew_to(&rpa_info);
}

void ble_periph_init(void)
{
    sm_bonding_info_t bind_info;
    ble_txpkt_init();
    ble_sm_param_init();
    gap_random_address_set_mode(GAP_PUBLIC_ADDRESS_TYPE);
    att_server_init(ble_get_profile_data());
    ble_service_init();
#if LE_CHECK_PEER_TYPE
    gatt_client_init();
    ble_client_init();
#endif // LE_CHECK_PEER_TYPE

    ble_rpa_param_init();

    if (bsp_ble_bind_state(0, &bind_info) && (bind_info.real_address_type == 1)) {
        gap_ral_dev_info_t ral_dev_info;
        ral_dev_info.priv_mode = 1;
        memcpy(ral_dev_info.peer_irk, bind_info.peer_irk.key, 16);
        ral_dev_info.addr.addr_type = bind_info.address_type;
        memcpy(&ral_dev_info.addr.addr, &bind_info.address, 6);
        ble_add_dev_to_ral_list(&ral_dev_info);
    }
}

void bsp_ble_init(void)
{
    memset(&ble_cb, 0x00, sizeof(ble_cb));

    bt_init();
    ble_init_callback_register(ble_periph_init);
    bt_setup();

    /* ADV Initialize */

    delay_5ms(20);

    if (ble_get_bonding_cnt()) {
        printf("ADV_DIR_IND!!\n");
        ble_dir_adv_param_init(true);
    } else {
        printf("ADV_UNDIR_IND!!\n");
        ble_adv_param_init(true);
    }
}

bool bsp_ble_bind_state(uint8_t index, sm_bonding_info_t* bind_info)
{
    sm_bonding_info_t* dev_bind_info = ble_get_bonding_info_for_index(index);

    memcpy(bind_info, dev_bind_info, sizeof(sm_bonding_info_t));

    return (0xff != bind_info->address_type);
}
