/** @file
 *
 * @API 文档
 *
 */

#ifndef __BLE_COMM__
#define __BLE_COMM__

#include "sdk_common.h"
#include "ble_db_discovery.h"
#include "sdk_errors.h"
#include "app_error.h"
#include "app_util.h"
#include "bsp_btn_ble.h"
#include "ble.h"
#include "ble_gap.h"
#include "ble_hci.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "nrf_sdh_soc.h"
#include "ble_nus_c.h"
#include "nrf_ble_gatt.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_ble_scan.h"
#include "app_timer.h"
#include "ble_conn_state.h"

#include "SEGGER_RTT.h"
#include "nrf_delay.h"
#include "main.h"
#include "queue.h"
#include "ringframe.h"
#include "ble_advdata.h"

// <<< Use Configuration Wizard in Context Menu >>>\r\n
#define APP_BLE_CONN_CFG_TAG 1

// <q> USE_LADDR  - 广播名称是否添加地址后缀
#ifndef USE_LADDR
#define USE_LADDR 1
#endif
// <q> USENAMEFR  - 扫描是否采用名字匹配
#ifndef USENAMEFR
#define USENAMEFR 1
#endif
// <q> USEMACNAME  - 采用mac地址作为蓝牙名称
#ifndef USEMACNAME
#define USEMACNAME 0
#endif

// <q> USEFIFO  - 采用FIFO方式发送
#ifndef USEFIFO
#define USEFIFO 1
#endif

#define TARFET_LEN_MAX NRF_BLE_SCAN_NAME_MAX_LEN

// <q> BLE_PRINTF  - 调试信息
#ifndef BLE_PRINTF
#define BLE_PRINTF 0
#endif
#if BLE_PRINTF
#define BLE_PRINT(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#else
#define BLE_PRINT(...) ;
#endif
#define APP_ERR_BASE 0

/**@brief 各种错误数据类型. */
enum
{
	APP_SUCCESS = APP_ERR_BASE,
	APP_ERR_DISCONN,
	APP_ERR_CONNECTED,
	APP_ERR_PARAMERR,
	APP_ERR_OVERLENGTH,
	APP_ERR_BUSY,
	APP_ERROR_RESOURCES,
};

/**@brief 报错函数.
 *
 * @param[in]      err_num       	 错误代码
 *
 * @warning 
 */
void err(int err_num);

/**@brief 扫描到的广播数据包回调事件类型
 *
 * @param[in]      unsigned short   广播数据包的长度
 * @param[out]     unsigned char *  接收到的完整广播数据包的指针
 * @param[in]      signed char      RSSI
 *
 * @warning 
 */
typedef void (*advdata_rep_handler_t)(unsigned char *, unsigned short ,signed char);

/**@brief 数据接收类型
 *
 * @warning 
 */
typedef void (*Ble_receive_handler_t)(unsigned char *, int);

/**@brief 蓝牙时间回调类型
 *
 * @warning 
 */
typedef void (*Ble_evt_cb)(void);

/**@brief 发送数据到从机
 *
 * @param[in]      bytes       要发送的数据的指针.
 * @param[in]      len  			 要发送的数据的长度
 *
 * @retval 0  			操作成功
 * @retval 1 				发送失败
 *
 * @warning 
 */
unsigned int send_bytes_server(uint8_t *bytes, uint16_t len);

/**@brief 发送数据到主机
 *
 * @param[in]      bytes       要发送的数据的指针.
 * @param[in]      len  			 要发送的数据的长度
 *
 * @retval 0  			操作成功
 * @retval 1 				发送失败
 *
 * @warning 
 */
unsigned int send_bytes_client(unsigned char *bytes, uint16_t len);

/**@brief 主机初始化
 *
 * @warning 
 */
void host_init(Ble_receive_handler_t receive_handler);

/**@brief 从机初始化
 *
 * @warning 
 */
void slave_init(Ble_receive_handler_t receive_handler);

/**@brief 从机角色获取链接是否建立
 *
 * @retval 1   链接已经建立
 * @retval 0   链接未建立
 *
 * @warning 
 */
unsigned char slave_isconnect(void);

/**@brief 主机角色获取链接是否建立
 *
 * @retval 1   链接已经建立
 * @retval 0   链接未建立
 *
 * @warning 
 */
unsigned char host_isconnect(void);

/**@brief 设置扫描名称
 *
 * @param[in]      name      要设置的名称
 * @param[in]      len       要设置的名称的长度
 *
 * @retval APP_SUCCESS            操作成功
 * @retval APP_ERR_CONNECTED      链接已经建立
 * @retval APP_ERR_OVERLENGTH     长度太长
 *
 * @warning 
 */
unsigned int host_set_scan_name(char *name, int len);

/**@brief 设置广播名称
 *
 * @param[in]      name      要设置的广播名称
 * @param[in]      len       要设置的广播名称的长度
 *
 * @retval APP_SUCCESS            操作成功 
 *
 * @warning 
 */
unsigned int slave_set_adv_name(char *name, int len);

/**@brief 获取当前正在广播的名称长度
 *
 * @param[out]     len  					 广播的名称长度
 *
 * @warning 
 */
void slave_get_advname_len(int *len);

/**@brief 获取当前正在广播的名称，要和void slave_get_advname_len(int *len);合用
 *
 * @param[in]      len    广播名称的长度
 * @param[out]     name   广播名称
 *
 * @warning 
 */
void slave_get_advname(char *name, int len);

/**@brief 注册一个在连接建立的时候的通知
 *
 * @param[in]      cb       要注册的回调函数指针
 *
 * @retval -1     要注册的回调已经存在
 * @retval 0 			注册成功
 * @retval -2     注册的队列已经满了
 *
 * @warning 
 */
int Ble_Host_Connectd_Evt_Regist(Ble_evt_cb cb);

/**@brief 注册一个在连接断开的时候的通知
 *
 * @param[in]      cb       要注册的回调函数指针
 *
 * @retval -1     要注册的回调已经存在
 * @retval 0 			注册成功
 * @retval -2     注册的队列已经满了
 *
 * @warning 
 */
int Ble_Host_Disconn_Evt_Regist(Ble_evt_cb cb);

/**@brief 注册一个在连接建立的时候的通知
 *
 * @param[in]      cb       要注册的回调函数指针
 *
 * @retval -1     要注册的回调已经存在
 * @retval 0 			注册成功
 * @retval -2     注册的队列已经满了
 *
 * @warning 
 */
int Ble_Slave_Connectd_Evt_Regist(Ble_evt_cb cb);

/**@brief 注册一个在连接断开的时候的通知
 *
 * @param[in]      cb       要注册的回调函数指针
 *
 * @retval -1     要注册的回调已经存在
 * @retval 0 			注册成功
 * @retval -2     注册的队列已经满了
 *
 * @warning 
 */
int Ble_Slave_Disconn_Evt_Regist(Ble_evt_cb cb);

/**@brief 作为主机时申请更新链接间隔
 *
 * @param[in]      min_conn_interval   最小链接间隔
 * @param[in]      max_conn_interval   最大链接间隔
 *  
 * @retval APP_ERR_PARAMERR   输如的参数错误
 * @retval APP_ERR_DISCONN    链接已经断开
 *
 * @warning 
 */
unsigned int Ble_update_conn_interval(float min_conn_interval, float max_conn_interval);

/**@brief 作为从机时申请更新链接间隔
 *
 * @param[in]      min_conn_interval   最小链接间隔
 * @param[in]      max_conn_interval   最大链接间隔
 *
 * @retval APP_ERR_BUSY       正处在一个申请流程中，此时不接受新的申请     
 * @retval APP_ERR_PARAMERR   输如的参数错误
 * @retval APP_ERR_DISCONN    链接已经断开
 *
 * @warning 
 */
unsigned int slave_update_conn_interval_request(float min_conn_interval, float max_conn_interval);

/**@brief 关闭广播
 *
 * @warning 
 */
void advertising_stop(void);

/**@brief 开启广播
 *
 * @warning 
 */
void advertising_start(void);

/**@brief 开启扫描
 *
 * @warning 
 */
void scan_start(void);

//关掉扫描直接调用  void nrf_ble_scan_stop(void);

/**@brief 略
 *
 * @warning 
 */
uint8_t Slave_Get7_5ms_interval(void);

/**@brief 作为从机角色的时候主动断开蓝牙链接
 *
 * @warning 
 */
void slave_disconnect(void);

/**@brief 作为主机角色的时候主动断开蓝牙链接
 *
 * @warning 
 */
void host_disconnect(void);

/**@brief 作为从机角色的时候获取连接参数
 *
 * @param[out]     p  获取到的链接参数的存放指针
 *
 * @warning 
 */
void slave_get_conn_params(ble_gap_conn_params_t *p);

/**@brief 作为主机角色的时候获取连接参数
 *
 * @param[out]     p  获取到的链接参数的存放指针
 *
 * @warning 
 */
void host_get_conn_params(ble_gap_conn_params_t *p);

/**@brief 从机广播初始化
 * @warning 
 */
void slave_adv_init(void);

/**@brief 作为从机角色的时候获取RSSI
 *
 * @retval 获取到的RSSI  
 *
 * @warning 
 */
signed char slave_get_rssi(void);

/**@brief 作为主机角色的时候获取RSSI
 *
 * @retval 获取到的RSSI  
 *
 * @warning 
 */
signed char host_get_rssi(void);

/**@brief 运动算法处理
 *
 * @param[in]      IS_HOST     是否是左鞋.
 * @param[in]      time_stamp  时间戳.
 * @param[in]      _acc        加速度.
 * @param[in]      _gry        陀螺仪.
 * @param[in]      front_mag   前磁力计.
 * @param[in]      back_mag    后磁力计.
 * @param[in]      _rssi       信号强度.
 *
 * @warning 
 */
void IMU_Process_motion_queue(uint8_t IS_HOST, int32_t time_stamp, int16_t* _acc,int16_t* _gry, int16_t* front_mag, int16_t* back_mag, uint8_t _rssi);

/**@brief 对齐功能驱动
 *
 * @details 
 * @warning 
 */
void IMU_Rec_data(uint8_t* pdat,uint8_t len);

/**@brief IMU_Dtalige 对齐函数
 * @warning 
 */
void IMU_Dtalige(void);

/**@brief 打开原始数据上传模式
 * @warning 
 */
void IMU_Dtalige_Rowdata_ON(void);

/**@brief 关闭原始数据上传模式
 * @warning 
 */
void IMU_Dtalige_Rowdata_OFF(void);

/**@brief 这个函数是在系统大循环中调的
 *
 * @warning 
 */
void send_bytes_client_pcs(void);

/**@brief Function for searching through encoded Advertising data for a complete local name.
 *
 * @param[in]    p_encoded_data Data buffer containing the encoded Advertising data.
 * @param[in]    data_len       Length of the data buffer \p p_encoded_data.
 * @param[in]    p_target_name  Name to search for.
 *
 * @retval true   If \p p_target_name was found among \p p_encoded_data, as a complete local name.
 * @retval false  If \p p_target_name was not found among \p p_encoded_data, or if \p p_encoded_data
 *                or \p p_target_name was NULL.
 */
bool advdata_name_find(uint8_t const * p_encoded_data,
                           uint16_t        data_len,
                           char    const * p_target_name);

/**@brief Function for searching through encoded Advertising data for a device shortened name.
 *
 * @param[in]    p_encoded_data     Data buffer containing the encoded Advertising data.
 * @param[in]    data_len           Length of the data buffer \p p_encoded_data.
 * @param[in]    p_target_name      Name to search for.
 * @param[in]    short_name_min_len Minimum length of the shortened name.
 *               For example, if the advertising data has a shortened name 'No' and this parameter is
 *               set to 4 with a target_name set to Nordic_XXX it will return false, but if
 *               the shortened name in the advertising data is 'Nord', it will return true.
 * @note: If the shortened name in the Advertising data has the same length as the target name,
 *        this function will return false, since this means that the complete name is actually
 *        longer, thus different than the target name.
 *
 * @retval true   If \p p_target_name was found among \p p_encoded_data, as short local name.
 * @retval false  If \p p_target_name was not found among \p p_encoded_data, or if \p p_encoded_data
 *                or \p p_target_name was NULL.
 */
bool advdata_short_name_find(uint8_t const * p_encoded_data,
                                 uint16_t        data_len,
                                 char    const * p_target_name,
                                 uint8_t const   short_name_min_len);
																 
/**@brief 这个函数用来注册收到广播数据包时候的事件.
 *
 * @param[in]   handler     需要注册的回调函数的函数指针
 *
 * @note: 			此函数每次调用都会覆盖上一次的注册的handler，建议只调用一次，注册成功后会在每次收到广播数据包以后产生事件回调。
 *
 */
void advdata_report_Evt_Regist(advdata_rep_handler_t handler);
																 
/**@brief 关闭扫描
 * @warning 
 */																 
void ST_scan_stop(void);

/**@brief 无条件打开扫描
 * @warning 
 *
 * @retval APP_ERROR_RESOURCES   radio占用过多，先关闭一个或多个链路后再打开就好了   
 * @retval APP_SUCCESS           操作成功
 *  			
 * @note:
 */
unsigned int ST_scan_start(void);																 
																 														 
#endif
