#include "include.h"
#include "ble_service.h"
#include "ble_user_service.h"


static att_service_handler_t    generic_access_service;
static att_service_handler_t    generic_attribute_service;
static uint16_t                 generic_attribute_client_config;

extern void ble_dir_adv_param_init(bool adv_en);
extern void ble_adv_param_init(bool adv_en);

AT(.com_sleep.ble.sleep)
bool ble_user_service_pending(void)
{
    // true: if will be break sleep when in sleep mode.
    return false;
}

static void ble_conn_param_check(void)
{
    uint16_t intv, lat, sup_to;

    ble_get_conn_param(ble_cb.con_hanle, &intv, &lat, &sup_to);

    if (intv != 6 || lat < 49) {
        ble_update_conn_param(ble_cb.con_hanle, 6, 67, 200);
    }
    else if (lat
             #if SYS_SLEEP_LEVEL
               && !sys_cb.sleep_sta
             #endif // SYS_SLEEP_LEVEL
               )
    {
        ble_disable_latency(ble_cb.con_hanle);
    }
}

static void ble_event_packet_handle(uint8_t event_type, uint8_t *param, uint16_t size)
{
    switch(event_type){
        case BLE_EVT_CONNECT:{
            memcpy(&ble_cb.con_hanle, &param[7], 2);
            ble_conn_param_check();
            printf("-->BLE_EVT_CONNECT:%x\n",ble_cb.con_hanle);
            param_ble_central_addr_write(&param[0]);
        } break;

        case BLE_EVT_DISCONNECT:{
            uint16_t con_handle;
            uint8_t disc_reason = param[2];
            memcpy(&con_handle, &param[0], 2);
            printf("-->BLE_EVT_DISCONNECT:%x, disc_reason %x\n",con_handle, disc_reason);
            ble_cb.con_hanle = 0;
            generic_attribute_client_config = CCCD_DFT;

            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);
            }
        } break;
        case BLE_EVT_CONNECT_PARAM_UPDATE_DONE: {
            printf("BLE_EVT_CONNECT_PARAM_UPDATE_DONE\n");
            u8 status = param[0];
            u16 handle = param[1] | (param[2] << 8);
            u16 interval = param[3] | (param[4] << 8);
            u16 latency = param[5] | (param[6] << 8);
            u16 timeout = param[7] | (param[8] << 8);
            printf("%d, %d, %d, %d, %d\n", status, handle, interval, latency, timeout);
            if (latency
            #if SYS_SLEEP_LEVEL
                && !sys_cb.sleep_sta
            #endif // SYS_SLEEP_LEVEL
                )
            {
                ble_disable_latency(ble_cb.con_hanle);
            }
        } break;
        case BLE_EVT_PAIRING_DONE:{
            gap_ral_dev_info_t ral_dev_info;
            sm_bonding_info_t bind_info;
            printf("%s BLE_EVT_PAIRING_DONE\n", __func__);

            if (bsp_ble_bind_state(0, &bind_info) && (bind_info.real_address_type == 1)) {
                ral_dev_info.priv_mode = 1;

                ral_dev_info.addr.addr_type = bind_info.address_type;
                printf("%s addr_type %x\n", __func__, ral_dev_info.addr.addr_type);

                memcpy(&ral_dev_info.addr.addr, &bind_info.address, 6);

                memcpy(ral_dev_info.peer_irk, bind_info.peer_irk.key, 16);

                ble_add_dev_to_ral_list(&ral_dev_info);
            }
        } break;

        default:
            break;
    }
}

static uint16_t service_read_callback(uint16_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size)
{
    printf("service_read_callback\n");

    if (attribute_handle == ATT_CHARACTERISTIC_GAP_DEVICE_NAME_01_VALUE_HANDLE) {
        u8 read_data[] = BLE_DEFAULT_DEVICE_NAME;
        u8 read_data_len = strlen(xcfg_cb.le_name);
        if (read_data_len > 0) {
            if (buffer) {
                memcpy(buffer, xcfg_cb.le_name, read_data_len);
            }
        } else {
            read_data_len = sizeof(read_data) - 1;
            if (buffer){
                memcpy(buffer, read_data, read_data_len);
                printf("user_service_read_callback 0x%x data[%d]: ", attribute_handle, buffer_size);
                print_r(buffer, buffer_size);
            }
        }

        return read_data_len;
    }

	return 0;
}

static int service_write_callback(uint16_t con_handle, uint16_t attribute_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size)
{
    printf("service_write_callback\n");

    if(attribute_handle == ATT_CHARACTERISTIC_GATT_SERVICE_CHANGED_01_CLIENT_CONFIGURATION_HANDLE){
        generic_attribute_client_config = GET_LE16(&buffer[0]);
    }

    return ATT_ERR_NO_ERR;
}

void ble_user_service_init(void)
{
    printf("ble_user_service_init\n");

    // register service with ATT Server
    generic_access_service.start_handle   = ATT_SERVICE_GAP_SERVICE_START_HANDLE;
    generic_access_service.end_handle     = ATT_SERVICE_GAP_SERVICE_END_HANDLE;
    generic_access_service.read_callback  = &service_read_callback;
    generic_access_service.write_callback = &service_write_callback;
    generic_access_service.event_handler  = &ble_event_packet_handle;
    att_server_register_service_handler(&generic_access_service);

    // register service with ATT Server
    generic_attribute_service.start_handle   = ATT_SERVICE_GATT_SERVICE_START_HANDLE;
    generic_attribute_service.end_handle     = ATT_SERVICE_GATT_SERVICE_END_HANDLE;
    generic_attribute_service.read_callback  = &service_read_callback;
    generic_attribute_service.write_callback = &service_write_callback;
    generic_attribute_service.event_handler  = &ble_event_packet_handle;
    att_server_register_service_handler(&generic_attribute_service);

    generic_attribute_client_config = 0;
}

AT(.text.app.proc.ble)
void ble_user_service_proc(void)
{
}
