/****************************************Copyright (c)************************************************
**                                                                                                 
**--------------File Info-----------------------------------------------------------------------------
** File          name:ble_nus.c
** Last modified Date:          
** Last       Version:		   
** Descriptions      :串口透传服务文件			
**---------------------------------------------------------------------------------------------------*/
#include "sdk_common.h"
//这里设置了串口透传服务程序模块的“编译开关”，所以要在sdk_config.h中启用BLE_NUS
#if NRF_MODULE_ENABLED(BLE_NUS)
#include "ble.h"
#include "ble_nus.h"
#include "ble_srv_common.h"
#include "nrf_log.h"

#if 0
#define NRF_LOG_MODULE_NAME ble_nus
#if BLE_NUS_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL       BLE_NUS_CONFIG_LOG_LEVEL
#define NRF_LOG_INFO_COLOR  BLE_NUS_CONFIG_INFO_COLOR
#define NRF_LOG_DEBUG_COLOR BLE_NUS_CONFIG_DEBUG_COLOR
#else // BLE_NUS_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL       0
#endif // BLE_NUS_CONFIG_LOG_ENABLED

NRF_LOG_MODULE_REGISTER();
#endif

#define BLE_NUS_MAX_RX_CHAR_LEN        BLE_NUS_MAX_DATA_LEN //RX特征最大长度（字节数）
#define BLE_NUS_MAX_TX_CHAR_LEN        BLE_NUS_MAX_DATA_LEN //TX特征最大长度（字节数）

//SoftDevice提交的“Write”事件处理函数
static void on_write(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
{
    //定义一个串口透传事件结构体变量，用于执行回调时传递参数
    ble_nus_evt_t                 evt;
    //定义write事件结构体指针并指向GATT事件的write
    ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;

    //清空evt结构体
    memset(&evt, 0, sizeof(ble_nus_evt_t));
	//指向串口透传实例
    evt.p_nus       = p_nus;
	//设置连接句柄
    evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
    //写RX特征值
    if ((p_evt_write->handle == p_nus->rx_handles.value_handle) &&
             (p_nus->data_handler != NULL))
    {
		//设置事件类型
        evt.type                  = BLE_NUS_EVT_RX_DATA;
		//设置数据
        evt.params.rx_data.p_data = p_evt_write->data;
		//设置数据长度
        evt.params.rx_data.length = p_evt_write->len;
        //执行回调
        p_nus->data_handler(&evt);
    }
    else
    {
        // Do Nothing. This event is not relevant for this service.
    }
}

//SoftDevice提交的“BLE_GATTS_EVT_HVN_TX_COMPLETE”事件处理函数
static void on_hvx_tx_complete(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
{
    //定义一个串口透传事件结构体变量evt，用于执行回调时传递参数
    ble_nus_evt_t              evt;
	//清零evt
	memset(&evt, 0, sizeof(ble_nus_evt_t));
	//设置事件类型
	evt.type        = BLE_NUS_EVT_TX_RDY;
	//指向串口透传服务实例
	evt.p_nus       = p_nus;
	//设置连接句柄
	evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
    //执行回调
	p_nus->data_handler(&evt);
}


//串口透传服务BLE事件监视者的事件回调函数
void ble_nus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
{
	//检查参数是否有效
    if ((p_context == NULL) || (p_ble_evt == NULL))
    {
        return;
    }
    //定义一个串口透传结构体指针并指向串口透传结构体
    ble_nus_t * p_nus = (ble_nus_t *)p_context;
    //判断事件类型
    switch (p_ble_evt->header.evt_id)
    {
		//写事件
        case BLE_GATTS_EVT_WRITE:
            on_write(p_nus, p_ble_evt);
            break;
        //TX就绪事件
        case BLE_GATTS_EVT_HVN_TX_COMPLETE:
            on_hvx_tx_complete(p_nus, p_ble_evt);
            break;

        default:
            // No implementation needed.
            break;
    }
}


//初始化串口透传服务
uint32_t ble_nus_init(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init)
{
    ret_code_t            err_code;
	//定义16位UUID结构体变量
    ble_uuid_t            ble_uuid;
	//定义128位UUID结构体变量，并初始化为串口透传服务UUID基数
    ble_uuid128_t         nus_base_uuid = NUS_BASE_UUID;
	//定义特征参数结构体变量
    ble_add_char_params_t add_char_params;
    //检查指针是否为NULL
    VERIFY_PARAM_NOT_NULL(p_nus);
    VERIFY_PARAM_NOT_NULL(p_nus_init);

    //拷贝串口透传服务初始化结构体中的事件句柄
    p_nus->data_handler = p_nus_init->data_handler;

    //将自定义UUID基数添加到SoftDevice
    err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus->uuid_type);
    VERIFY_SUCCESS(err_code);
    //UUID类型和数值赋值给ble_uuid变量
    ble_uuid.type = BLE_UUID_TYPE_BLE;
    ble_uuid.uuid = BLE_UUID_NUS_SERVICE;

    //添加串口透传服务
    err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
                                        &ble_uuid,
                                        &p_nus->service_handle);
    VERIFY_SUCCESS(err_code);
    /*---------------------以下代码添加RX特征--------------------*/
    //添加RX特征
	  //配置参数之前先清零add_char_params
    memset(&add_char_params, 0, sizeof(add_char_params));
	  //RX特征的UUID
    add_char_params.uuid                     = BLE_UUID_NUS_RX_CHARACTERISTIC;
	  //RX特征的UUID类型
    add_char_params.uuid_type                = p_nus->uuid_type;
	  //设置RX特征值的最大长度
    add_char_params.max_len                  = BLE_NUS_MAX_RX_CHAR_LEN;
	  //设置RX特征值的初始长度
    add_char_params.init_len                 = sizeof(uint8_t);
	  //设置RX的特征值长度为可变长度
    add_char_params.is_var_len               = true;
	  //设置RX特征的性质支持写
    add_char_params.char_props.write         = 1;
	  //设置RX特性的性质支持读
	add_char_params.char_props.read          = 1;
	  //设置RX特征的性质支持无响应写
    add_char_params.char_props.write_wo_resp = 1;
      //设置读/写RX特征值的安全需求：无安全性
    add_char_params.read_access  = SEC_OPEN;
    add_char_params.write_access = SEC_OPEN;
      //为串口透传服务添加RX特征
    err_code = characteristic_add(p_nus->service_handle, &add_char_params, &p_nus->rx_handles);
    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }
	    /*---------------------添加RX特征-END------------------------*/
	
    /*---------------------以下代码添加TX特征--------------------*/
    //添加TX特征
      //配置参数之前先清零add_char_params
    memset(&add_char_params, 0, sizeof(add_char_params));
	  //TX特征的UUID
    add_char_params.uuid              = BLE_UUID_NUS_TX_CHARACTERISTIC;
	  //TX特征的UUID类型
    add_char_params.uuid_type         = p_nus->uuid_type;
	  //设置TX特征值的最大长度
    add_char_params.max_len           = BLE_NUS_MAX_TX_CHAR_LEN;
	  //设置TX特征值的初始长度
    add_char_params.init_len          = sizeof(uint8_t);
	  //设置TX的特征值长度为可变长度
    add_char_params.is_var_len        = true;
	  //设置TX特征的性质：支持通知
    add_char_params.char_props.notify = 1;
	  //设置TX特性的性质：支持读
	add_char_params.char_props.read   = 1;
    //设置读/写RX特征值的安全需求：无安全性
    add_char_params.read_access       = SEC_OPEN;
    add_char_params.write_access      = SEC_OPEN;
    add_char_params.cccd_write_access = SEC_OPEN;
    //为串口透传服务添加TX特征
    return characteristic_add(p_nus->service_handle, &add_char_params, &p_nus->tx_handles);
        /*---------------------添加TX特征-END------------------------*/
}

//蓝牙数据上传发送，并进行反馈
 uint32_t ble_nus_data_send(ble_nus_t * p_nus,
                           uint8_t   * p_data,
                           uint16_t  * p_length,
                           uint16_t    conn_handle)
{
    ble_gatts_hvx_params_t     hvx_params;
    //验证p_uarts没有指向NULL
    VERIFY_PARAM_NOT_NULL(p_nus);
	
      //如果连接句柄无效，表示没有和主机建立连接，返回NRF_ERROR_NOT_FOUND
    if (conn_handle == BLE_CONN_HANDLE_INVALID)
    {
        return NRF_ERROR_NOT_FOUND;
    }

    if (*p_length > BLE_NUS_MAX_DATA_LEN)
    {
        return NRF_ERROR_INVALID_PARAM;
    }
      //设置之前先清零hvx_params
    memset(&hvx_params, 0, sizeof(hvx_params));
      //TX特征值句柄
    hvx_params.handle = p_nus->tx_handles.value_handle;
	  //发送的数据
    hvx_params.p_data = p_data;
	  //发送的数据长度
    hvx_params.p_len  = p_length;
	  //类型为通知
    hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
      //发送TX特征值通知
    return sd_ble_gatts_hvx(conn_handle, &hvx_params);
}


#endif // NRF_MODULE_ENABLED(BLE_NUS)
