/* This code belongs in ble_cus.c*/
#include "sdk_common.h"
#include "ble_srv_common.h"
#include "ble_cus.h"
#include <string.h>
#include "nrf_gpio.h"
#include "boards.h"
#include "nrf_log.h"
#include "nrf_delay.h"
#include "nrf_nvmc.h"

/**@brief Function for initializing the Custom Service.
 *
 * @param[out]  p_cus       Custom Service structure. This structure will have to be supplied by
 *                          the application. It will be initialized by this function, and will later
 *                          be used to identify this particular service instance.
 * @param[in]   p_cus_init  Information needed to initialize the service.
 *
 * @return      NRF_SUCCESS on successful initialization of service, otherwise an error code.
 */

uint32_t ble_cus_init(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init);

uint32_t custom_value_char_add_1(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init);
uint32_t custom_value_char_add_2(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init);
uint32_t custom_value_char_add_3(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init);
uint32_t custom_value_char_add_4(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init);
uint32_t custom_value_char_add_5(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init);
uint32_t custom_value_char_add_6(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init);
uint32_t custom_value_char_add_7(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init);
uint32_t custom_value_char_add_8(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init);
uint32_t custom_value_char_add_9(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init);
uint32_t custom_value_char_add_10(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init);

void ble_cus_on_ble_evt( ble_evt_t const * p_ble_evt, void * p_context);

uint32_t ble_cus_init(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
{
    if (p_cus == NULL || p_cus_init == NULL)
    {
        return NRF_ERROR_NULL;
    }

    uint32_t   err_code;
    ble_uuid_t ble_uuid;

    // Initialize service structure
    p_cus->conn_handle               = BLE_CONN_HANDLE_INVALID;

    // Add Custom Service UUID
    ble_uuid128_t base_uuid = {CUSTOM_SERVICE_UUID_BASE};
    err_code =  sd_ble_uuid_vs_add(&base_uuid, &p_cus->uuid_type);
    VERIFY_SUCCESS(err_code);
    
    ble_uuid.type = p_cus->uuid_type;
    ble_uuid.uuid = CUSTOM_SERVICE_UUID;

    // Add the Custom Service
    err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_cus->service_handle);
    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    // Add Custom value characteristic
    err_code = custom_value_char_add_1(p_cus, p_cus_init);// This line is not strictly needed, but if you plan to do more, don't return this value
    APP_ERROR_CHECK(err_code);
    err_code = custom_value_char_add_2(p_cus, p_cus_init);
    APP_ERROR_CHECK(err_code);  
    err_code = custom_value_char_add_3(p_cus, p_cus_init);
    APP_ERROR_CHECK(err_code);  
    err_code = custom_value_char_add_4(p_cus, p_cus_init);
    APP_ERROR_CHECK(err_code);  
    err_code = custom_value_char_add_5(p_cus, p_cus_init);
    APP_ERROR_CHECK(err_code);  
    err_code = custom_value_char_add_6(p_cus, p_cus_init);
    APP_ERROR_CHECK(err_code);  
    err_code = custom_value_char_add_7(p_cus, p_cus_init);
    APP_ERROR_CHECK(err_code);  
    err_code = custom_value_char_add_8(p_cus, p_cus_init);
    APP_ERROR_CHECK(err_code);  
    err_code = custom_value_char_add_9(p_cus, p_cus_init);
    APP_ERROR_CHECK(err_code);  
    err_code = custom_value_char_add_10(p_cus, p_cus_init);
    APP_ERROR_CHECK(err_code); 
  
    return err_code;
}

/**@brief Function for adding the Custom Value characteristic.
 *
 * @param[in]   p_cus        Custom Service structure.
 * @param[in]   p_cus_init   Information needed to initialize the service.
 *
 * @return      NRF_SUCCESS on success, otherwise an error code.
 */
uint32_t custom_value_char_add_1(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
{
    uint32_t            err_code;
    ble_gatts_char_md_t char_md;
    ble_gatts_attr_md_t cccd_md;
    ble_gatts_attr_t    attr_char_value;
    ble_uuid_t          ble_uuid;
    ble_gatts_attr_md_t attr_md;

    memset(&char_md, 0, sizeof(char_md));

    char_md.char_props.read   = 1;
    char_md.char_props.write  = 1;
    char_md.char_props.notify = 0; 

    char_md.p_char_user_desc  = NULL;
    char_md.p_char_pf         = NULL;
    char_md.p_user_desc_md    = NULL;
    char_md.p_cccd_md         = NULL; 
    char_md.p_sccd_md         = NULL;

    memset(&attr_md, 0, sizeof(attr_md));

    attr_md.read_perm  = p_cus_init->custom_value_char_attr_md.read_perm;
    attr_md.write_perm = p_cus_init->custom_value_char_attr_md.write_perm;
    attr_md.vloc       = BLE_GATTS_VLOC_STACK;
    attr_md.rd_auth    = 0;
    attr_md.wr_auth    = 0;
    attr_md.vlen       = 0;

    ble_uuid.type = p_cus->uuid_type;
    ble_uuid.uuid = CUSTOM_VALUE_CHAR_UUID_1;

    memset(&attr_char_value, 0, sizeof(attr_char_value));

    attr_char_value.p_uuid    = &ble_uuid;
    attr_char_value.p_attr_md = &attr_md;
    attr_char_value.init_len  = sizeof(uint8_t);
    attr_char_value.init_offs = 0;
    attr_char_value.max_len   = sizeof(uint8_t);


    err_code = sd_ble_gatts_characteristic_add(p_cus->service_handle, &char_md,
                                                   &attr_char_value,
                                                   &p_cus->custom_value_handles_1);

    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    return NRF_SUCCESS;
}

uint32_t custom_value_char_add_2(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
{
    uint32_t            err_code;
    ble_gatts_char_md_t char_md;
    ble_gatts_attr_md_t cccd_md;
    ble_gatts_attr_t    attr_char_value;
    ble_uuid_t          ble_uuid;
    ble_gatts_attr_md_t attr_md;

    memset(&char_md, 0, sizeof(char_md));

    char_md.char_props.read   = 1;
    char_md.char_props.write  = 1;
    char_md.char_props.notify = 0; 

    char_md.p_char_user_desc  = NULL;
    char_md.p_char_pf         = NULL;
    char_md.p_user_desc_md    = NULL;
    char_md.p_cccd_md         = NULL; 
    char_md.p_sccd_md         = NULL;

    memset(&attr_md, 0, sizeof(attr_md));

    attr_md.read_perm  = p_cus_init->custom_value_char_attr_md.read_perm;
    attr_md.write_perm = p_cus_init->custom_value_char_attr_md.write_perm;
    attr_md.vloc       = BLE_GATTS_VLOC_STACK;
    attr_md.rd_auth    = 0;
    attr_md.wr_auth    = 0;
    attr_md.vlen       = 0;

    ble_uuid.type = p_cus->uuid_type;
    ble_uuid.uuid = CUSTOM_VALUE_CHAR_UUID_2;

    memset(&attr_char_value, 0, sizeof(attr_char_value));

    attr_char_value.p_uuid    = &ble_uuid;
    attr_char_value.p_attr_md = &attr_md;
    attr_char_value.init_len  = sizeof(uint8_t);
    attr_char_value.init_offs = 0;
    attr_char_value.max_len   = sizeof(uint8_t);


    err_code = sd_ble_gatts_characteristic_add(p_cus->service_handle, &char_md,
                                                   &attr_char_value,
                                                   &p_cus->custom_value_handles_2);

    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    return NRF_SUCCESS;
}

uint32_t custom_value_char_add_3(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
{
    uint32_t            err_code;
    ble_gatts_char_md_t char_md;
    ble_gatts_attr_md_t cccd_md;
    ble_gatts_attr_t    attr_char_value;
    ble_uuid_t          ble_uuid;
    ble_gatts_attr_md_t attr_md;

    memset(&char_md, 0, sizeof(char_md));

    char_md.char_props.read   = 1;
    char_md.char_props.write  = 1;
    char_md.char_props.notify = 0; 

    char_md.p_char_user_desc  = NULL;
    char_md.p_char_pf         = NULL;
    char_md.p_user_desc_md    = NULL;
    char_md.p_cccd_md         = NULL; 
    char_md.p_sccd_md         = NULL;

    memset(&attr_md, 0, sizeof(attr_md));

    attr_md.read_perm  = p_cus_init->custom_value_char_attr_md.read_perm;
    attr_md.write_perm = p_cus_init->custom_value_char_attr_md.write_perm;
    attr_md.vloc       = BLE_GATTS_VLOC_STACK;
    attr_md.rd_auth    = 0;
    attr_md.wr_auth    = 0;
    attr_md.vlen       = 0;

    ble_uuid.type = p_cus->uuid_type;
    ble_uuid.uuid = CUSTOM_VALUE_CHAR_UUID_3;

    memset(&attr_char_value, 0, sizeof(attr_char_value));

    attr_char_value.p_uuid    = &ble_uuid;
    attr_char_value.p_attr_md = &attr_md;
    attr_char_value.init_len  = sizeof(uint8_t);
    attr_char_value.init_offs = 0;
    attr_char_value.max_len   = sizeof(uint8_t);


    err_code = sd_ble_gatts_characteristic_add(p_cus->service_handle, &char_md,
                                                   &attr_char_value,
                                                   &p_cus->custom_value_handles_3);

    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    return NRF_SUCCESS;
}
uint32_t custom_value_char_add_4(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
{
    uint32_t            err_code;
    ble_gatts_char_md_t char_md;
    ble_gatts_attr_md_t cccd_md;
    ble_gatts_attr_t    attr_char_value;
    ble_uuid_t          ble_uuid;
    ble_gatts_attr_md_t attr_md;

    memset(&char_md, 0, sizeof(char_md));

    char_md.char_props.read   = 1;
    char_md.char_props.write  = 1;
    char_md.char_props.notify = 0; 

    char_md.p_char_user_desc  = NULL;
    char_md.p_char_pf         = NULL;
    char_md.p_user_desc_md    = NULL;
    char_md.p_cccd_md         = NULL; 
    char_md.p_sccd_md         = NULL;

    memset(&attr_md, 0, sizeof(attr_md));

    attr_md.read_perm  = p_cus_init->custom_value_char_attr_md.read_perm;
    attr_md.write_perm = p_cus_init->custom_value_char_attr_md.write_perm;
    attr_md.vloc       = BLE_GATTS_VLOC_STACK;
    attr_md.rd_auth    = 0;
    attr_md.wr_auth    = 0;
    attr_md.vlen       = 0;

    ble_uuid.type = p_cus->uuid_type;
    ble_uuid.uuid = CUSTOM_VALUE_CHAR_UUID_4;

    memset(&attr_char_value, 0, sizeof(attr_char_value));

    attr_char_value.p_uuid    = &ble_uuid;
    attr_char_value.p_attr_md = &attr_md;
    attr_char_value.init_len  = sizeof(uint8_t);
    attr_char_value.init_offs = 0;
    attr_char_value.max_len   = sizeof(uint8_t);


    err_code = sd_ble_gatts_characteristic_add(p_cus->service_handle, &char_md,
                                                   &attr_char_value,
                                                   &p_cus->custom_value_handles_4);

    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    return NRF_SUCCESS;
}
uint32_t custom_value_char_add_5(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
{
    uint32_t            err_code;
    ble_gatts_char_md_t char_md;
    ble_gatts_attr_md_t cccd_md;
    ble_gatts_attr_t    attr_char_value;
    ble_uuid_t          ble_uuid;
    ble_gatts_attr_md_t attr_md;

    memset(&char_md, 0, sizeof(char_md));

    char_md.char_props.read   = 1;
    char_md.char_props.write  = 1;
    char_md.char_props.notify = 0; 

    char_md.p_char_user_desc  = NULL;
    char_md.p_char_pf         = NULL;
    char_md.p_user_desc_md    = NULL;
    char_md.p_cccd_md         = NULL; 
    char_md.p_sccd_md         = NULL;

    memset(&attr_md, 0, sizeof(attr_md));

    attr_md.read_perm = p_cus_init->custom_value_char_attr_md.read_perm;
    attr_md.write_perm = p_cus_init->custom_value_char_attr_md.write_perm;
    attr_md.vloc       = BLE_GATTS_VLOC_STACK;
    attr_md.rd_auth    = 0;
    attr_md.wr_auth    = 0;
    attr_md.vlen       = 0;

    ble_uuid.type = p_cus->uuid_type;
    ble_uuid.uuid = CUSTOM_VALUE_CHAR_UUID_5;

    memset(&attr_char_value, 0, sizeof(attr_char_value));

    attr_char_value.p_uuid    = &ble_uuid;
    attr_char_value.p_attr_md = &attr_md;
    attr_char_value.init_len  = sizeof(uint8_t);
    attr_char_value.init_offs = 0;
    attr_char_value.max_len   = sizeof(uint8_t);


    err_code = sd_ble_gatts_characteristic_add(p_cus->service_handle, &char_md,
                                                   &attr_char_value,
                                                   &p_cus->custom_value_handles_5);

    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    return NRF_SUCCESS;
}
uint32_t custom_value_char_add_6(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
{
    uint32_t            err_code;
    ble_gatts_char_md_t char_md;
    ble_gatts_attr_md_t cccd_md;
    ble_gatts_attr_t    attr_char_value;
    ble_uuid_t          ble_uuid;
    ble_gatts_attr_md_t attr_md;

    memset(&char_md, 0, sizeof(char_md));

    char_md.char_props.read   = 1;
    char_md.char_props.write  = 1;
    char_md.char_props.notify = 0; 

    char_md.p_char_user_desc  = NULL;
    char_md.p_char_pf         = NULL;
    char_md.p_user_desc_md    = NULL;
    char_md.p_cccd_md         = NULL; 
    char_md.p_sccd_md         = NULL;

    memset(&attr_md, 0, sizeof(attr_md));

    attr_md.read_perm  = p_cus_init->custom_value_char_attr_md.read_perm;
    attr_md.write_perm = p_cus_init->custom_value_char_attr_md.write_perm;
    attr_md.vloc       = BLE_GATTS_VLOC_STACK;
    attr_md.rd_auth    = 0;
    attr_md.wr_auth    = 0;
    attr_md.vlen       = 0;

    ble_uuid.type = p_cus->uuid_type;
    ble_uuid.uuid = CUSTOM_VALUE_CHAR_UUID_6;

    memset(&attr_char_value, 0, sizeof(attr_char_value));

    attr_char_value.p_uuid    = &ble_uuid;
    attr_char_value.p_attr_md = &attr_md;
    attr_char_value.init_len  = sizeof(uint8_t);
    attr_char_value.init_offs = 0;
    attr_char_value.max_len   = sizeof(uint8_t);


    err_code = sd_ble_gatts_characteristic_add(p_cus->service_handle, &char_md,
                                                   &attr_char_value,
                                                   &p_cus->custom_value_handles_6);

    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    return NRF_SUCCESS;
}
uint32_t custom_value_char_add_7(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
{
    uint32_t            err_code;
    ble_gatts_char_md_t char_md;
    ble_gatts_attr_md_t cccd_md;
    ble_gatts_attr_t    attr_char_value;
    ble_uuid_t          ble_uuid;
    ble_gatts_attr_md_t attr_md;

    memset(&char_md, 0, sizeof(char_md));

    char_md.char_props.read   = 1;
    char_md.char_props.write  = 1;
    char_md.char_props.notify = 0; 

    char_md.p_char_user_desc  = NULL;
    char_md.p_char_pf         = NULL;
    char_md.p_user_desc_md    = NULL;
    char_md.p_cccd_md         = NULL; 
    char_md.p_sccd_md         = NULL;

    memset(&attr_md, 0, sizeof(attr_md));

    attr_md.read_perm  = p_cus_init->custom_value_char_attr_md.read_perm;
    attr_md.write_perm = p_cus_init->custom_value_char_attr_md.write_perm;
    attr_md.vloc       = BLE_GATTS_VLOC_STACK;
    attr_md.rd_auth    = 0;
    attr_md.wr_auth    = 0;
    attr_md.vlen       = 0;

    ble_uuid.type = p_cus->uuid_type;
    ble_uuid.uuid = CUSTOM_VALUE_CHAR_UUID_7;

    memset(&attr_char_value, 0, sizeof(attr_char_value));

    attr_char_value.p_uuid    = &ble_uuid;
    attr_char_value.p_attr_md = &attr_md;
    attr_char_value.init_len  = sizeof(uint8_t);
    attr_char_value.init_offs = 0;
    attr_char_value.max_len   = sizeof(uint8_t);


    err_code = sd_ble_gatts_characteristic_add(p_cus->service_handle, &char_md,
                                                   &attr_char_value,
                                                   &p_cus->custom_value_handles_7);

    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    return NRF_SUCCESS;
}
uint32_t custom_value_char_add_8(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
{
    uint32_t            err_code;
    ble_gatts_char_md_t char_md;
    ble_gatts_attr_md_t cccd_md;
    ble_gatts_attr_t    attr_char_value;
    ble_uuid_t          ble_uuid;
    ble_gatts_attr_md_t attr_md;

    memset(&char_md, 0, sizeof(char_md));

    char_md.char_props.read   = 1;
    char_md.char_props.write  = 1;
    char_md.char_props.notify = 0; 

    char_md.p_char_user_desc  = NULL;
    char_md.p_char_pf         = NULL;
    char_md.p_user_desc_md    = NULL;
    char_md.p_cccd_md         = NULL; 
    char_md.p_sccd_md         = NULL;

    memset(&attr_md, 0, sizeof(attr_md));

    attr_md.read_perm  = p_cus_init->custom_value_char_attr_md.read_perm;
    attr_md.write_perm = p_cus_init->custom_value_char_attr_md.write_perm;
    attr_md.vloc       = BLE_GATTS_VLOC_STACK;
    attr_md.rd_auth    = 0;
    attr_md.wr_auth    = 0;
    attr_md.vlen       = 0;

    ble_uuid.type = p_cus->uuid_type;
    ble_uuid.uuid = CUSTOM_VALUE_CHAR_UUID_8;

    memset(&attr_char_value, 0, sizeof(attr_char_value));

    attr_char_value.p_uuid    = &ble_uuid;
    attr_char_value.p_attr_md = &attr_md;
    attr_char_value.init_len  = sizeof(uint8_t);
    attr_char_value.init_offs = 0;
    attr_char_value.max_len   = sizeof(uint8_t);


    err_code = sd_ble_gatts_characteristic_add(p_cus->service_handle, &char_md,
                                                   &attr_char_value,
                                                   &p_cus->custom_value_handles_8);

    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    return NRF_SUCCESS;
}
uint32_t custom_value_char_add_9(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
{
    uint32_t            err_code;
    ble_gatts_char_md_t char_md;
    ble_gatts_attr_md_t cccd_md;
    ble_gatts_attr_t    attr_char_value;
    ble_uuid_t          ble_uuid;
    ble_gatts_attr_md_t attr_md;

    memset(&char_md, 0, sizeof(char_md));

    char_md.char_props.read   = 1;
    char_md.char_props.write  = 1;
    char_md.char_props.notify = 0; 

    char_md.p_char_user_desc  = NULL;
    char_md.p_char_pf         = NULL;
    char_md.p_user_desc_md    = NULL;
    char_md.p_cccd_md         = NULL; 
    char_md.p_sccd_md         = NULL;

    memset(&attr_md, 0, sizeof(attr_md));

    attr_md.read_perm  = p_cus_init->custom_value_char_attr_md.read_perm;
    attr_md.write_perm = p_cus_init->custom_value_char_attr_md.write_perm;
    attr_md.vloc       = BLE_GATTS_VLOC_STACK;
    attr_md.rd_auth    = 0;
    attr_md.wr_auth    = 0;
    attr_md.vlen       = 0;

    ble_uuid.type = p_cus->uuid_type;
    ble_uuid.uuid = CUSTOM_VALUE_CHAR_UUID_9;

    memset(&attr_char_value, 0, sizeof(attr_char_value));

    attr_char_value.p_uuid    = &ble_uuid;
    attr_char_value.p_attr_md = &attr_md;
    attr_char_value.init_len  = sizeof(uint8_t);
    attr_char_value.init_offs = 0;
    attr_char_value.max_len   = sizeof(uint8_t);


    err_code = sd_ble_gatts_characteristic_add(p_cus->service_handle, &char_md,
                                                   &attr_char_value,
                                                   &p_cus->custom_value_handles_9);

    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    return NRF_SUCCESS;
}
uint32_t custom_value_char_add_10(ble_cus_t * p_cus, const ble_cus_init_t * p_cus_init)
{
    uint32_t            err_code;
    ble_gatts_char_md_t char_md;
    ble_gatts_attr_md_t cccd_md;
    ble_gatts_attr_t    attr_char_value;
    ble_uuid_t          ble_uuid;
    ble_gatts_attr_md_t attr_md;

    memset(&char_md, 0, sizeof(char_md));

    char_md.char_props.read   = 1;
    char_md.char_props.write  = 1;
    char_md.char_props.notify = 0; 

    char_md.p_char_user_desc  = NULL;
    char_md.p_char_pf         = NULL;
    char_md.p_user_desc_md    = NULL;
    char_md.p_cccd_md         = NULL; 
    char_md.p_sccd_md         = NULL;

    memset(&attr_md, 0, sizeof(attr_md));

    attr_md.read_perm  = p_cus_init->custom_value_char_attr_md.read_perm;
    attr_md.write_perm = p_cus_init->custom_value_char_attr_md.write_perm;
    attr_md.vloc       = BLE_GATTS_VLOC_STACK;
    attr_md.rd_auth    = 0;
    attr_md.wr_auth    = 0;
    attr_md.vlen       = 0;

    ble_uuid.type = p_cus->uuid_type;
    ble_uuid.uuid = CUSTOM_VALUE_CHAR_UUID_10;

    memset(&attr_char_value, 0, sizeof(attr_char_value));

    attr_char_value.p_uuid    = &ble_uuid;
    attr_char_value.p_attr_md = &attr_md;
    attr_char_value.init_len  = sizeof(uint8_t);
    attr_char_value.init_offs = 0;
    attr_char_value.max_len   = sizeof(uint8_t);


    err_code = sd_ble_gatts_characteristic_add(p_cus->service_handle, &char_md,
                                                   &attr_char_value,
                                                   &p_cus->custom_value_handles_10);

    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    return NRF_SUCCESS;
}





/**@brief Function for handling the Connect event.
 *
 * @param[in]   p_cus       Custom Service structure.
 * @param[in]   p_ble_evt   Event received from the BLE stack.
 */
void on_connect(ble_cus_t * p_cus, ble_evt_t const * p_ble_evt)
{
    p_cus->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
}

/**@brief Function for handling the Disconnect event.
 *
 * @param[in]   p_cus       Custom Service structure.
 * @param[in]   p_ble_evt   Event received from the BLE stack.
 */
void on_disconnect(ble_cus_t * p_cus, ble_evt_t const * p_ble_evt)
{
    UNUSED_PARAMETER(p_ble_evt);
    p_cus->conn_handle = BLE_CONN_HANDLE_INVALID;
}
/**@brief Function for handling the Write event.
 *
 * @param[in]   p_cus       Custom Service structure.
 * @param[in]   p_ble_evt   Event received from the BLE stack.
 */
void on_write(ble_cus_t * p_cus, ble_evt_t const * p_ble_evt)
{
    // Calculate the start address of a page as shown in the video
    // make sure you always use the part of the flash which is not being used otherwise it might
    // overwrite your program code causing the device to malfunction or behave in unpredicted manner.
    ret_code_t err_code;
    ble_gatts_evt_write_t *p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
    
    // Check if the handle passed with the event matches the Custom Value Characteristic handle.
//    if (p_evt_write->handle == p_cus->custom_value_handles.value_handle)
      if (p_evt_write->handle != NULL)
    {
      switch(p_evt_write->uuid.uuid)
      {

      case CUSTOM_VALUE_CHAR_UUID_1:
        NRF_LOG_INFO("Write On 1");
        ble_cus_custom_value_update(p_cus, 0x21,1);
      break;

      case CUSTOM_VALUE_CHAR_UUID_2:
        NRF_LOG_INFO("Write On 2");
        ble_cus_custom_value_update(p_cus, 0x22,2);
      break;

      case CUSTOM_VALUE_CHAR_UUID_3:
        NRF_LOG_INFO("Write On 3");
        ble_cus_custom_value_update(p_cus, 0x23,3);
      break;

      case CUSTOM_VALUE_CHAR_UUID_4:
        NRF_LOG_INFO("Write On 4");
        ble_cus_custom_value_update(p_cus, 0x24,4);
      break;

      case CUSTOM_VALUE_CHAR_UUID_5:
        NRF_LOG_INFO("Write On 5");
        ble_cus_custom_value_update(p_cus, 0x25,5);
      break;

      case CUSTOM_VALUE_CHAR_UUID_6:
        NRF_LOG_INFO("Write On 6");
        ble_cus_custom_value_update(p_cus, 0x26,6);
      break;

      case CUSTOM_VALUE_CHAR_UUID_7:
        NRF_LOG_INFO("Write On 7");
        ble_cus_custom_value_update(p_cus, 0x27,7);
      break;

      case CUSTOM_VALUE_CHAR_UUID_8:
        NRF_LOG_INFO("Write On 8");
        ble_cus_custom_value_update(p_cus, 0x28,8);
      break;

      case CUSTOM_VALUE_CHAR_UUID_9:
        NRF_LOG_INFO("Write On 9");
        ble_cus_custom_value_update(p_cus, 0x29,9);
      break;

      case CUSTOM_VALUE_CHAR_UUID_10:
        NRF_LOG_INFO("Write On 10");
        ble_cus_custom_value_update(p_cus, 0x30,10);
      break;

     default:
        NRF_LOG_INFO("Write On Default");
      break;
      }

    }

}

void ble_cus_on_ble_evt( ble_evt_t const * p_ble_evt, void * p_context)
{
    ble_cus_t * p_cus = (ble_cus_t *) p_context;
    
    if (p_cus == NULL || p_ble_evt == NULL)
    {
        return;
    }
   switch (p_ble_evt->header.evt_id)
    {
    
        case BLE_GAP_EVT_CONNECTED:
            on_connect(p_cus, p_ble_evt);
            break;

        case BLE_GAP_EVT_DISCONNECTED:
            on_disconnect(p_cus, p_ble_evt);
            break;
       case BLE_GATTS_EVT_WRITE:
           on_write(p_cus, p_ble_evt);
           break;
        default:
            // No implementation needed.
            break;
    }
}
uint32_t ble_cus_custom_value_update(ble_cus_t * p_cus, uint8_t custom_value,uint8_t char_no)
{
    NRF_LOG_INFO("Feedback Setting");
    if (p_cus == NULL)
    {
        return NRF_ERROR_NULL;
    }

    uint32_t err_code = NRF_SUCCESS;
    ble_gatts_value_t gatts_value;

    // Initialize value struct.
    memset(&gatts_value, 0, sizeof(gatts_value));

    gatts_value.len     = sizeof(uint8_t);
    gatts_value.offset  = 0;
    gatts_value.p_value = &custom_value;


      switch(char_no)
      {
      case 1:

      // Update database.
      err_code = sd_ble_gatts_value_set(p_cus->conn_handle,
                                        p_cus->custom_value_handles_1.value_handle,
                                        &gatts_value);
      if (err_code != NRF_SUCCESS)
      {
          return err_code;
      }

      // Send value if connected and notifying.
      if ((p_cus->conn_handle != BLE_CONN_HANDLE_INVALID)) 
      {
          ble_gatts_hvx_params_t hvx_params;

          memset(&hvx_params, 0, sizeof(hvx_params));

          hvx_params.handle = p_cus->custom_value_handles_1.value_handle;
          hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
          hvx_params.offset = gatts_value.offset;
          hvx_params.p_len  = &gatts_value.len;
          hvx_params.p_data = gatts_value.p_value;

          err_code = sd_ble_gatts_hvx(p_cus->conn_handle, &hvx_params);
          NRF_LOG_INFO("Feedback On 1");

      }
      else
      {
          err_code = NRF_ERROR_INVALID_STATE;
      }

      break;
      case 2:
      // Update database.
      err_code = sd_ble_gatts_value_set(p_cus->conn_handle,
                                        p_cus->custom_value_handles_2.value_handle,
                                        &gatts_value);
      if (err_code != NRF_SUCCESS)
      {
          return err_code;
      }

      // Send value if connected and notifying.
      if ((p_cus->conn_handle != BLE_CONN_HANDLE_INVALID)) 
      {
          ble_gatts_hvx_params_t hvx_params;

          memset(&hvx_params, 0, sizeof(hvx_params));

          hvx_params.handle = p_cus->custom_value_handles_2.value_handle;
          hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
          hvx_params.offset = gatts_value.offset;
          hvx_params.p_len  = &gatts_value.len;
          hvx_params.p_data = gatts_value.p_value;

          err_code = sd_ble_gatts_hvx(p_cus->conn_handle, &hvx_params);
          NRF_LOG_INFO("Feedback On 2");
      }
      else
      {
          err_code = NRF_ERROR_INVALID_STATE;
      }

      break;

      case 3:

      // Update database.
      err_code = sd_ble_gatts_value_set(p_cus->conn_handle,
                                        p_cus->custom_value_handles_3.value_handle,
                                        &gatts_value);
      if (err_code != NRF_SUCCESS)
      {
          return err_code;
      }

      // Send value if connected and notifying.
      if ((p_cus->conn_handle != BLE_CONN_HANDLE_INVALID)) 
      {
          ble_gatts_hvx_params_t hvx_params;

          memset(&hvx_params, 0, sizeof(hvx_params));

          hvx_params.handle = p_cus->custom_value_handles_3.value_handle;
          hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
          hvx_params.offset = gatts_value.offset;
          hvx_params.p_len  = &gatts_value.len;
          hvx_params.p_data = gatts_value.p_value;

          err_code = sd_ble_gatts_hvx(p_cus->conn_handle, &hvx_params);
          NRF_LOG_INFO("Feedback On 3");
      }
      else
      {
          err_code = NRF_ERROR_INVALID_STATE;
      }
      break;

      case 4:

      // Update database.
      err_code = sd_ble_gatts_value_set(p_cus->conn_handle,
                                        p_cus->custom_value_handles_4.value_handle,
                                        &gatts_value);

      if (err_code != NRF_SUCCESS)
      {
          return err_code;
      }
      // Send value if connected and notifying.
      if ((p_cus->conn_handle != BLE_CONN_HANDLE_INVALID)) 
      {
          ble_gatts_hvx_params_t hvx_params;

          memset(&hvx_params, 0, sizeof(hvx_params));

          hvx_params.handle = p_cus->custom_value_handles_4.value_handle;
          hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
          hvx_params.offset = gatts_value.offset;
          hvx_params.p_len  = &gatts_value.len;
          hvx_params.p_data = gatts_value.p_value;

          err_code = sd_ble_gatts_hvx(p_cus->conn_handle, &hvx_params);
          NRF_LOG_INFO("Feedback On 4");

      }
      else
      {
          err_code = NRF_ERROR_INVALID_STATE;
       }
      break;

      case 5:
      // Update database.
      err_code = sd_ble_gatts_value_set(p_cus->conn_handle,
                                        p_cus->custom_value_handles_5.value_handle,
                                        &gatts_value);
      if (err_code != NRF_SUCCESS)
      {
          return err_code;
      }

      // Send value if connected and notifying.
      if ((p_cus->conn_handle != BLE_CONN_HANDLE_INVALID)) 
      {
          ble_gatts_hvx_params_t hvx_params;

          memset(&hvx_params, 0, sizeof(hvx_params));

          hvx_params.handle = p_cus->custom_value_handles_5.value_handle;
          hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
          hvx_params.offset = gatts_value.offset;
          hvx_params.p_len  = &gatts_value.len;
          hvx_params.p_data = gatts_value.p_value;

          err_code = sd_ble_gatts_hvx(p_cus->conn_handle, &hvx_params);
          NRF_LOG_INFO("Feedback On 5");
      }
      else
      {
          err_code = NRF_ERROR_INVALID_STATE;
      }

      break;
      case 6:
      // Update database.
      err_code = sd_ble_gatts_value_set(p_cus->conn_handle,
                                        p_cus->custom_value_handles_6.value_handle,
                                        &gatts_value);
      if (err_code != NRF_SUCCESS)
      {
          return err_code;
      }

      // Send value if connected and notifying.
      if ((p_cus->conn_handle != BLE_CONN_HANDLE_INVALID)) 
      {
          ble_gatts_hvx_params_t hvx_params;

          memset(&hvx_params, 0, sizeof(hvx_params));

          hvx_params.handle = p_cus->custom_value_handles_6.value_handle;
          hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
          hvx_params.offset = gatts_value.offset;
          hvx_params.p_len  = &gatts_value.len;
          hvx_params.p_data = gatts_value.p_value;

          err_code = sd_ble_gatts_hvx(p_cus->conn_handle, &hvx_params);
          NRF_LOG_INFO("Feedback On 6");
      }
      else
      {
          err_code = NRF_ERROR_INVALID_STATE;
      }

      break;
      case 7:
      // Update database.
      err_code = sd_ble_gatts_value_set(p_cus->conn_handle,
                                        p_cus->custom_value_handles_7.value_handle,
                                        &gatts_value);
      if (err_code != NRF_SUCCESS)
      {
          return err_code;
      }

      // Send value if connected and notifying.
      if ((p_cus->conn_handle != BLE_CONN_HANDLE_INVALID)) 
      {
          ble_gatts_hvx_params_t hvx_params;

          memset(&hvx_params, 0, sizeof(hvx_params));

          hvx_params.handle = p_cus->custom_value_handles_7.value_handle;
          hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
          hvx_params.offset = gatts_value.offset;
          hvx_params.p_len  = &gatts_value.len;
          hvx_params.p_data = gatts_value.p_value;

          err_code = sd_ble_gatts_hvx(p_cus->conn_handle, &hvx_params);
          NRF_LOG_INFO("Feedback On 7");
      }
      else
      {
          err_code = NRF_ERROR_INVALID_STATE;
      }

      break;
      case 8:
      // Update database.
      err_code = sd_ble_gatts_value_set(p_cus->conn_handle,
                                        p_cus->custom_value_handles_8.value_handle,
                                        &gatts_value);
      if (err_code != NRF_SUCCESS)
      {
          return err_code;
      }

      // Send value if connected and notifying.
      if ((p_cus->conn_handle != BLE_CONN_HANDLE_INVALID)) 
      {
          ble_gatts_hvx_params_t hvx_params;

          memset(&hvx_params, 0, sizeof(hvx_params));

          hvx_params.handle = p_cus->custom_value_handles_8.value_handle;
          hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
          hvx_params.offset = gatts_value.offset;
          hvx_params.p_len  = &gatts_value.len;
          hvx_params.p_data = gatts_value.p_value;

          err_code = sd_ble_gatts_hvx(p_cus->conn_handle, &hvx_params);
          NRF_LOG_INFO("Feedback On 8");
      }
      else
      {
          err_code = NRF_ERROR_INVALID_STATE;
      }

      break;
      case 9:
      // Update database.
      err_code = sd_ble_gatts_value_set(p_cus->conn_handle,
                                        p_cus->custom_value_handles_9.value_handle,
                                        &gatts_value);
      if (err_code != NRF_SUCCESS)
      {
          return err_code;
      }

      // Send value if connected and notifying.
      if ((p_cus->conn_handle != BLE_CONN_HANDLE_INVALID)) 
      {
          ble_gatts_hvx_params_t hvx_params;

          memset(&hvx_params, 0, sizeof(hvx_params));

          hvx_params.handle = p_cus->custom_value_handles_9.value_handle;
          hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
          hvx_params.offset = gatts_value.offset;
          hvx_params.p_len  = &gatts_value.len;
          hvx_params.p_data = gatts_value.p_value;

          err_code = sd_ble_gatts_hvx(p_cus->conn_handle, &hvx_params);
          NRF_LOG_INFO("Feedback On 9");
      }
      else
      {
          err_code = NRF_ERROR_INVALID_STATE;
      }

      break;
      case 10:
     // Update database.
      err_code = sd_ble_gatts_value_set(p_cus->conn_handle,
                                        p_cus->custom_value_handles_10.value_handle,
                                        &gatts_value);
      if (err_code != NRF_SUCCESS)
      {
          return err_code;
      }

      // Send value if connected and notifying.
      if ((p_cus->conn_handle != BLE_CONN_HANDLE_INVALID)) 
      {
          ble_gatts_hvx_params_t hvx_params;

          memset(&hvx_params, 0, sizeof(hvx_params));

          hvx_params.handle = p_cus->custom_value_handles_10.value_handle;
          hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
          hvx_params.offset = gatts_value.offset;
          hvx_params.p_len  = &gatts_value.len;
          hvx_params.p_data = gatts_value.p_value;

          err_code = sd_ble_gatts_hvx(p_cus->conn_handle, &hvx_params);
          NRF_LOG_INFO("Feedback On 10");
      }
      else
      {
          err_code = NRF_ERROR_INVALID_STATE;
      }

      break;

}

    return err_code;
}