/*********************************************************************
 * INCLUDES
 */
#include "CONFIG.h"
#include "gattprofile.h"
#include "multiCentral.h"
#include "bsp_uart.h"
#include "log.h"

#include "bsp_valve.h"

#undef LOG_ENABLE
#define LOG_ENABLE 1

/*********************************************************************
 * MACROS
 */

// Length of bd addr as a string
#define B_ADDR_STR_LEN 15

/*********************************************************************
 * CONSTANTS
 */
// Maximum number of scan responses
#define DEFAULT_MAX_SCAN_RES 10

// Scan duration in 0.625ms
#define DEFAULT_SCAN_DURATION 2400 // 2400*0.625 = 1500ms

// Connection min interval in 1.25ms
#define DEFAULT_MIN_CONNECTION_INTERVAL 80

// Connection max interval in 1.25ms
#define DEFAULT_MAX_CONNECTION_INTERVAL 80 * 5

// Connection supervision timeout in 10ms
/*修改为最大值*/
#define DEFAULT_CONNECTION_TIMEOUT 100 // 32s

// Discovey mode (limited, general, all)
#define DEFAULT_DISCOVERY_MODE DEVDISC_MODE_ALL

// TRUE to use active scan
#define DEFAULT_DISCOVERY_ACTIVE_SCAN TRUE

// TRUE to use white list during discovery
#define DEFAULT_DISCOVERY_WHITE_LIST FALSE

// TRUE to use high scan duty cycle when creating link
#define DEFAULT_LINK_HIGH_DUTY_CYCLE FALSE

// TRUE to use white list when creating link
#define DEFAULT_LINK_WHITE_LIST FALSE

// Default read RSSI period in 0.625ms
#define DEFAULT_RSSI_PERIOD 2400

// Minimum connection interval (units of 1.25ms)
#define DEFAULT_UPDATE_MIN_CONN_INTERVAL 20

// Maximum connection interval (units of 1.25ms)
#define DEFAULT_UPDATE_MAX_CONN_INTERVAL 100

// Slave latency to use parameter update
#define DEFAULT_UPDATE_SLAVE_LATENCY 5

// Supervision timeout value (units of 10ms)
#define DEFAULT_UPDATE_CONN_TIMEOUT 600

// Default passcode
#define DEFAULT_PASSCODE 0

// Default GAP pairing mode
#define DEFAULT_PAIRING_MODE GAPBOND_PAIRING_MODE_WAIT_FOR_REQ

// Default MITM mode (TRUE to require passcode or OOB when pairing)
#define DEFAULT_MITM_MODE TRUE

// Default bonding mode, TRUE to bond, max bonding 6 devices
#define DEFAULT_BONDING_MODE TRUE

// Default GAP bonding I/O capabilities
#define DEFAULT_IO_CAPABILITIES GAPBOND_IO_CAP_NO_INPUT_NO_OUTPUT

// Default service discovery timer delay in 0.625ms
#define DEFAULT_SVC_DISCOVERY_DELAY 1600

// Default parameter update delay in 0.625ms
#define DEFAULT_PARAM_UPDATE_DELAY 3200

// Default read or write timer delay in 0.625ms
#define DEFAULT_READ_OR_WRITE_DELAY 1600

// Default write CCCD delay in 0.625ms
#define DEFAULT_WRITE_CCCD_DELAY 1600

// Establish link timeout in 0.625ms
#define ESTABLISH_LINK_TIMEOUT 3200

// Application states
enum
{
    BLE_STATE_IDLE,
    BLE_STATE_CONNECTING,
    BLE_STATE_CONNECTED,
    BLE_STATE_DISCONNECTING
};

// Discovery states
enum
{
    BLE_DISC_STATE_IDLE, // Idle
    BLE_DISC_STATE_SVC,  // Service discovery
    BLE_DISC_STATE_CHAR, // Characteristic discovery
    BLE_DISC_STATE_CCCD, // client characteristic configuration discovery
};

/*********************************************************************
 * TYPEDEFS
 */

/*********************************************************************
 * GLOBAL VARIABLES
 */

/*********************************************************************
 * EXTERNAL VARIABLES
 */

/*********************************************************************
 * EXTERNAL FUNCTIONS
 */

/*********************************************************************
 * LOCAL VARIABLES
 */

// Task ID for internal task/event processing
static uint8_t centralTaskId;

// Number of scan results
static uint8_t centralScanRes;

// Scan result list
static gapDevRec_t centralDevList[DEFAULT_MAX_SCAN_RES];

// Peer device address
static peerAddrDefItem_t PeerAddrDef[CENTRAL_MAX_CONNECTION] = {
    // {0xcf, 0xb4, 0x8f, 0x10, 0x53, 0x5c},
    // {0xe1, 0X51, 0x89, 0x88, 0x19, 0x70},
    {0xb6, 0xb4, 0x8f, 0x10, 0x53, 0x5c},
    // {0x03, 0x02, 0x03, 0xE4, 0xC2, 0x84},
};

// Connection item list
centralConnItem_t centralConnList[CENTRAL_MAX_CONNECTION];

// Value to write
static uint8_t centralCharVal = 0x01;

// Value read/write toggle
static uint8_t centralDoWrite = TRUE;

/*********************************************************************
 * LOCAL FUNCTIONS
 */
static void centralProcessGATTMsg(gattMsgEvent_t *pMsg);
static void centralRssiCB(uint16_t connHandle, int8_t rssi);
static void centralEventCB(gapRoleEvent_t *pEvent);
static void centralHciMTUChangeCB(uint16_t connHandle, uint16_t maxTxOctets, uint16_t maxRxOctets);
static void centralPasscodeCB(uint8_t *deviceAddr, uint16_t connectionHandle,
                              uint8_t uiInputs, uint8_t uiOutputs);
static void centralPairStateCB(uint16_t connHandle, uint8_t state, uint8_t status);
static uint16_t connect0_ProcessEvent(uint8_t task_id, uint16_t events);
static void central_ProcessTMOSMsg(tmos_event_hdr_t *pMsg);
static void centralGATTDiscoveryEvent(uint8_t connItem, gattMsgEvent_t *pMsg);
static void centralConnIistStartDiscovery_0(void);
static void centralAddDeviceInfo(uint8_t *pAddr, uint8_t addrType);
static void centralInitConnItem(uint8_t task_id, centralConnItem_t *centralConnList);
static uint8_t centralAddrCmp(peerAddrDefItem_t *PeerAddrDef, uint8_t *addr);

int BSP_Master_Receive_Data(uint8_t task_id, uint8_t *data, uint16_t len);
/*********************************************************************
 * PROFILE CALLBACKS
 */

// GAP Role Callbacks
static gapCentralRoleCB_t centralRoleCB = {
    centralRssiCB,        // RSSI callback
    centralEventCB,       // Event callback
    centralHciMTUChangeCB // MTU change callback
};

// Bond Manager Callbacks
static gapBondCBs_t centralBondCB = {
    centralPasscodeCB,
    centralPairStateCB};

/*********************************************************************
 * PUBLIC FUNCTIONS
 */

/*********************************************************************
 * @fn      Central_Init
 *
 * @brief   Initialization function for the Central App Task.
 *          This is called during initialization and should contain
 *          any application specific initialization (ie. hardware
 *          initialization/setup, table initialization, power up
 *          notification).
 *
 * @param   task_id - the ID assigned by TMOS.  This ID should be
 *                    used to send messages and set timers.
 *
 * @return  none
 */
void Central_Init()
{
    centralTaskId = TMOS_ProcessEventRegister(Central_ProcessEvent);

    // Setup GAP
    GAP_SetParamValue(TGAP_DISC_SCAN, DEFAULT_SCAN_DURATION);
    GAP_SetParamValue(TGAP_CONN_EST_INT_MIN, DEFAULT_MIN_CONNECTION_INTERVAL);
    GAP_SetParamValue(TGAP_CONN_EST_INT_MAX, DEFAULT_MAX_CONNECTION_INTERVAL);
    GAP_SetParamValue(TGAP_CONN_EST_SUPERV_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT);

    // Setup the GAP Bond Manager
    {
        uint32_t passkey = DEFAULT_PASSCODE;
        uint8_t pairMode = DEFAULT_PAIRING_MODE;
        uint8_t mitm     = DEFAULT_MITM_MODE;
        uint8_t ioCap    = DEFAULT_IO_CAPABILITIES;
        uint8_t bonding  = DEFAULT_BONDING_MODE;

        GAPBondMgr_SetParameter(GAPBOND_CENT_DEFAULT_PASSCODE, sizeof(uint32_t), &passkey);
        GAPBondMgr_SetParameter(GAPBOND_CENT_PAIRING_MODE, sizeof(uint8_t), &pairMode);
        GAPBondMgr_SetParameter(GAPBOND_CENT_MITM_PROTECTION, sizeof(uint8_t), &mitm);
        GAPBondMgr_SetParameter(GAPBOND_CENT_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
        GAPBondMgr_SetParameter(GAPBOND_CENT_BONDING_ENABLED, sizeof(uint8_t), &bonding);
    }

    // Init Connection Item
    centralInitConnItem(centralTaskId, centralConnList);
    // Initialize GATT Client
    GATT_InitClient();
    // Register to receive incoming ATT Indications/Notifications
    GATT_RegisterForInd(centralTaskId);
    // Setup a delayed profile startup
    tmos_set_event(centralTaskId, START_DEVICE_EVT);
}

/*********************************************************************
 * @fn      centralInitConnItem
 *
 * @brief   Init Connection Item
 *
 * @param   task_id -
 *          centralConnList -
 *
 * @return  NULL
 */
static void centralInitConnItem(uint8_t task_id, centralConnItem_t *centralConnList)
{
    uint8_t connItem;
    for (connItem = 0; connItem < CENTRAL_MAX_CONNECTION; connItem++)
    {
        // 每个连接的任务通过taskID区分
        centralConnList[connItem].taskID              = TMOS_ProcessEventRegister(Central_ProcessEvent);
        centralConnList[connItem].connHandle          = GAP_CONNHANDLE_INIT;
        centralConnList[connItem].state               = BLE_STATE_IDLE;
        centralConnList[connItem].discState           = BLE_DISC_STATE_IDLE;
        centralConnList[connItem].procedureInProgress = FALSE;
        centralConnList[connItem].charHdl             = 0;
        centralConnList[connItem].svcStartHdl         = 0;
        centralConnList[connItem].svcEndHdl           = 0;
        centralConnList[connItem].cccHdl              = 0;
    }
}

/*********************************************************************
 * @fn      Central_ProcessEvent
 *
 * @brief   Central Application Task event processor.  This function
 *          is called to process all events for the task.  Events
 *          include timers, messages and any other user defined events.
 *
 * @param   task_id  - The TMOS assigned task ID.
 * @param   events - events to process.  This is a bit map and can
 *                   contain more than one event.
 *
 * @return  events not processed
 */
uint16_t Central_ProcessEvent(uint8_t task_id, uint16_t events)
{
    if (events & SYS_EVENT_MSG)
    {
        uint8_t *pMsg;

        if ((pMsg = tmos_msg_receive(centralTaskId)) != NULL)
        {
            central_ProcessTMOSMsg((tmos_event_hdr_t *)pMsg);
            // Release the TMOS message
            tmos_msg_deallocate(pMsg);
        }
        // return unprocessed events
        return (events ^ SYS_EVENT_MSG);
    }

    if (events & START_DEVICE_EVT)
    {
        // Start the Device
        GAPRole_CentralStartDevice(centralTaskId, &centralBondCB, &centralRoleCB);
        return (events ^ START_DEVICE_EVT);
    }

    if (events & ESTABLISH_LINK_TIMEOUT_EVT)
    {
        GAPRole_TerminateLink(INVALID_CONNHANDLE);
        return (events ^ ESTABLISH_LINK_TIMEOUT_EVT);
    }

    // 连接0的任务处理
    if (task_id == centralConnList[CONNECT0_ITEM].taskID)
    {
        return connect0_ProcessEvent(task_id, events);
    }
    // 连接1的任务处理
    else if (task_id == centralConnList[CONNECT1_ITEM].taskID)
    {
    }
    // 连接2的任务处理
    //    else if(task_id == centralConnList[CONNECT2_ITEM].taskID)
    //    {
    //    }
    // Discard unknown events
    return 0;
}

/*********************************************************************
 * @fn      connect0_ProcessEvent
 *
 * @brief   Process an incoming task message.
 *
 * @param   pMsg - message to process
 *
 * @return  none
 */
static uint16_t connect0_ProcessEvent(uint8_t task_id, uint16_t events)
{
    if (events & START_SVC_DISCOVERY_EVT)
    {
        // start service discovery
        centralConnIistStartDiscovery_0();
        return (events ^ START_SVC_DISCOVERY_EVT);
    }
    if (events & START_READ_OR_WRITE_EVT)
    {
        if (centralConnList[CONNECT0_ITEM].procedureInProgress == FALSE)
        {
            if (centralDoWrite)
            {
                // Do a write
                attWriteReq_t req;

                req.cmd    = FALSE;
                req.sig    = FALSE;
                req.handle = centralConnList[CONNECT0_ITEM].charHdl;
                req.len    = 1;
                req.pValue = GATT_bm_alloc(centralConnList[CONNECT0_ITEM].connHandle, ATT_WRITE_REQ, req.len, NULL, 0);
                if (req.pValue != NULL)
                {
                    *req.pValue = centralCharVal;

                    if (GATT_WriteCharValue(centralConnList[CONNECT0_ITEM].connHandle, &req, centralTaskId) == SUCCESS)
                    {
                        centralConnList[CONNECT0_ITEM].procedureInProgress = TRUE;
                        centralDoWrite                                     = !centralDoWrite;
                        tmos_start_task(centralConnList[CONNECT0_ITEM].taskID, START_READ_OR_WRITE_EVT, DEFAULT_READ_OR_WRITE_DELAY);
                    }
                    else
                    {
                        GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);
                    }
                }
            }
            else
            {
                // Do a read
                attReadReq_t req;

                req.handle = centralConnList[CONNECT0_ITEM].charHdl;
                if (GATT_ReadCharValue(centralConnList[CONNECT0_ITEM].connHandle, &req, centralTaskId) == SUCCESS)
                {
                    centralConnList[CONNECT0_ITEM].procedureInProgress = TRUE;
                    centralDoWrite                                     = !centralDoWrite;
                }
            }
        }
        return (events ^ START_READ_OR_WRITE_EVT);
    }
    if (events & CH2_READ_EVT)
    {
        logDebug("CH2_READ_EVT\r\n");
        if (centralConnList[CONNECT0_ITEM].procedureInProgress == FALSE)
        {
            // read
            attReadReq_t req;

            req.handle = centralConnList[CONNECT0_ITEM].charHd2;
            if (GATT_ReadCharValue(centralConnList[CONNECT0_ITEM].connHandle, &req, centralTaskId) == SUCCESS)
            {
                centralConnList[CONNECT0_ITEM].procedureInProgress = TRUE;
                tmos_start_task(centralConnList[CONNECT0_ITEM].taskID, CH2_READ_EVT, 160000);
            }
        }
        return (events ^ CH2_READ_EVT);
    }
    if (events & CH3_WRITE_EVT)
    {
        logDebug("CH3_WRITE_EVT\r\n");
        if (centralConnList[CONNECT0_ITEM].procedureInProgress == FALSE)
        {
            logDebug("centralConnList CH3_WRITE_EVT\n");
            static uint8_t sendcnt = 0;
            attWriteReq_t req;

            req.cmd    = FALSE;
            req.sig    = FALSE;
            req.handle = centralConnList[CONNECT0_ITEM].charHd3;
            logDebug("handle:%x\r\n", req.handle);
            req.len    = 3;
            req.pValue = GATT_bm_alloc(centralConnList[CONNECT0_ITEM].connHandle, ATT_WRITE_REQ, req.len, NULL, 0);
            if (req.pValue != NULL)
            {
                logDebug("req.pValue != NULL\r\n");
                req.pValue[0] = 0x11;
                req.pValue[1] = 0x22;
                req.pValue[2] = sendcnt++;

                if (GATT_WriteCharValue(centralConnList[CONNECT0_ITEM].connHandle, &req, centralTaskId) == SUCCESS)
                {
                    centralConnList[CONNECT0_ITEM].procedureInProgress = TRUE;
                    tmos_start_task(centralConnList[CONNECT0_ITEM].taskID, CH3_WRITE_EVT, 3200);
                    logDebug("GATT_WriteCharValue\r\n");
                }
                else
                {
                    GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);
                }
            }
        }
        return (events ^ CH3_WRITE_EVT);
    }
    if (events & CH4_NOTI_EVT)
    {
        logDebug("CH4_NOTI_EVT\r\n");
        if (centralConnList[CONNECT0_ITEM].procedureInProgress == FALSE)
        {
            // Do a write
            attWriteReq_t req;
            logDebug("CH4_NOTI_EVT handle:%x\r\n", req.handle);
            req.cmd    = FALSE;
            req.sig    = FALSE;
            req.handle = centralConnList[CONNECT0_ITEM].charHd4;
            req.len    = 2;
            req.pValue = GATT_bm_alloc(centralConnList[CONNECT0_ITEM].connHandle, ATT_WRITE_REQ, req.len, NULL, 0); // 内存申请
            if (req.pValue != NULL)
            {
                logDebug("CH4_NOTI_EVT req.pValue != NULL\r\n");
                req.pValue[0] = 1;
                req.pValue[1] = 0;

                if (GATT_WriteCharValue(centralConnList[CONNECT0_ITEM].connHandle, &req, centralTaskId) == SUCCESS) // 发送
                {
                    logDebug("GATT_WriteCharValue  CH4_NOTI_EVT\r\n");
                    centralConnList[CONNECT0_ITEM].procedureInProgress = TRUE;
                }
                else
                {
                    GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ); // 释放内存
                }
            }
        }
        return (events ^ CH4_NOTI_EVT);
    }
    // if (events & START_WRITE_CCCD_EVT)
    // {
    //     if (centralConnList[CONNECT0_ITEM].procedureInProgress == FALSE)
    //     {
    //         // Do a write
    //         attWriteReq_t req;

    //         req.cmd    = FALSE;
    //         req.sig    = FALSE;
    //         req.handle = centralConnList[CONNECT0_ITEM].cccHdl;
    //         req.len    = 2;
    //         req.pValue = GATT_bm_alloc(centralConnList[CONNECT0_ITEM].connHandle, ATT_WRITE_REQ, req.len, NULL, 0);
    //         if (req.pValue != NULL)
    //         {
    //             req.pValue[0] = 1;
    //             req.pValue[1] = 0;

    //             if (GATT_WriteCharValue(centralConnList[CONNECT0_ITEM].connHandle, &req, centralTaskId) == SUCCESS)
    //             {
    //                 centralConnList[CONNECT0_ITEM].procedureInProgress = TRUE;
    //             }
    //             else
    //             {
    //                 GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);
    //             }
    //         }
    //     }
    //     return (events ^ START_WRITE_CCCD_EVT);
    // }
    if (events & START_READ_RSSI_EVT)
    {
        GAPRole_ReadRssiCmd(centralConnList[CONNECT0_ITEM].connHandle);
        tmos_start_task(centralConnList[CONNECT0_ITEM].taskID, START_READ_RSSI_EVT, DEFAULT_RSSI_PERIOD);
        return (events ^ START_READ_RSSI_EVT);
    }
    if (events & START_PARAM_UPDATE_EVT)
    {
        // start connect parameter update
        GAPRole_UpdateLink(centralConnList[CONNECT0_ITEM].connHandle,
                           DEFAULT_UPDATE_MIN_CONN_INTERVAL,
                           DEFAULT_UPDATE_MAX_CONN_INTERVAL,
                           DEFAULT_UPDATE_SLAVE_LATENCY,
                           DEFAULT_UPDATE_CONN_TIMEOUT);

        return (events ^ START_PARAM_UPDATE_EVT);
    }
    // Discard unknown events
    return 0;
}
/*********************************************************************
 * @fn      central_ProcessTMOSMsg
 *
 * @brief   Process an incoming task message.
 *
 * @param   pMsg - message to process
 *
 * @return  none
 */
static void central_ProcessTMOSMsg(tmos_event_hdr_t *pMsg)
{
    switch (pMsg->event)
    {
        case GATT_MSG_EVENT:
            centralProcessGATTMsg((gattMsgEvent_t *)pMsg);
            break;
    }
}

/*********************************************************************
 * @fn      centralProcessGATTMsg
 *
 * @brief   Process GATT messages
 *
 * @return  none
 */
static void centralProcessGATTMsg(gattMsgEvent_t *pMsg)
{
    uint8_t connItem;
    for (connItem = 0; connItem < CENTRAL_MAX_CONNECTION; connItem++)
    {
        if (centralConnList[connItem].connHandle == pMsg->connHandle)
            break;
    }
    if (connItem == CENTRAL_MAX_CONNECTION)
    {
        return;
        // Should not go there
    }

    if (centralConnList[connItem].state != BLE_STATE_CONNECTED)
    {
        // In case a GATT message came after a connection has dropped,
        // ignore the message
        GATT_bm_free(&pMsg->msg, pMsg->method);
        return;
    }

    if ((pMsg->method == ATT_EXCHANGE_MTU_RSP) ||
        ((pMsg->method == ATT_ERROR_RSP) &&
         (pMsg->msg.errorRsp.reqOpcode == ATT_EXCHANGE_MTU_REQ)))
    {
        if (pMsg->method == ATT_ERROR_RSP)
        {
            uint8_t status = pMsg->msg.errorRsp.errCode;

            logDebug("Exchange MTU Error: %x\r\n", status);
        }
        centralConnList[connItem].procedureInProgress = FALSE;
    }

    if (pMsg->method == ATT_MTU_UPDATED_EVENT)
    {
        logDebug("MTU: %x\r\n", pMsg->msg.mtuEvt.MTU);
    }

    if ((pMsg->method == ATT_READ_RSP) ||
        ((pMsg->method == ATT_ERROR_RSP) &&
         (pMsg->msg.errorRsp.reqOpcode == ATT_READ_REQ)))
    {
        if (pMsg->method == ATT_ERROR_RSP)
        {
            uint8_t status = pMsg->msg.errorRsp.errCode;

            logDebug("Read Error: %x\r\n", status);
        }
        else
        {
            // After a successful read, display the read value
            logDebug("Read rsp: ");
            logHexDumpAll(pMsg->msg.readRsp.pValue, pMsg->msg.readRsp.len);
        }
        centralConnList[connItem].procedureInProgress = FALSE;
    }
    else if ((pMsg->method == ATT_WRITE_RSP) ||
             ((pMsg->method == ATT_ERROR_RSP) &&
              (pMsg->msg.errorRsp.reqOpcode == ATT_WRITE_REQ)))
    {
        if (pMsg->method == ATT_ERROR_RSP == ATT_ERROR_RSP)
        {
            uint8_t status = pMsg->msg.errorRsp.errCode;

            logDebug("Write Error: %x\r\n", status);
        }
        else
        {
            // After a succesful write, display the value that was written and increment value
            logDebug("Write sent: %x\r\n", centralCharVal);
        }

        centralConnList[connItem].procedureInProgress = FALSE;
    }
    else if (pMsg->method == ATT_HANDLE_VALUE_NOTI)
    {
        logDebug("Noti: ");
        logHexDumpAll(pMsg->msg.handleValueNoti.pValue, pMsg->msg.handleValueNoti.len);
        if (connItem == CONNECT0_ITEM)
        {
            BSP_Master_Receive_Data(CONNECT0_ITEM, pMsg->msg.handleValueNoti.pValue, pMsg->msg.handleValueNoti.len);
        }
    }
    else if (centralConnList[connItem].discState != BLE_DISC_STATE_IDLE)
    {
        centralGATTDiscoveryEvent(connItem, pMsg);
    }
    GATT_bm_free(&pMsg->msg, pMsg->method);
}

/*********************************************************************
 * @fn      centralRssiCB
 *
 * @brief   RSSI callback.
 *
 * @param   connHandle - connection handle
 * @param   rssi - RSSI
 *
 * @return  none
 */
static void centralRssiCB(uint16_t connHandle, int8_t rssi)
{
    logDebug("RSSI -%d dB Conn - %x \r\n", -rssi, connHandle);
}

/*********************************************************************
 * @fn      centralHciMTUChangeCB
 *
 * @brief   MTU changed callback.
 *
 * @param   maxTxOctets - Max tx octets
 * @param   maxRxOctets - Max rx octets
 *
 * @return  none
 */
static void centralHciMTUChangeCB(uint16_t connHandle, uint16_t maxTxOctets, uint16_t maxRxOctets)
{
}

/*********************************************************************
 * @fn      centralEventCB
 *
 * @brief   Central event callback function.
 *
 * @param   pEvent - pointer to event structure
 *
 * @return  none
 */
static void centralEventCB(gapRoleEvent_t *pEvent)
{
    switch (pEvent->gap.opcode)
    {
        case GAP_DEVICE_INIT_DONE_EVENT:
        {
            logDebug("Discovering...\r\n");
            GAPRole_CentralStartDiscovery(DEFAULT_DISCOVERY_MODE,
                                          DEFAULT_DISCOVERY_ACTIVE_SCAN,
                                          DEFAULT_DISCOVERY_WHITE_LIST);
        }
        break;

        case GAP_DEVICE_INFO_EVENT:
        {
            // Add device to list
            centralAddDeviceInfo(pEvent->deviceInfo.addr, pEvent->deviceInfo.addrType);
        }
        break;

        case GAP_DEVICE_DISCOVERY_EVENT:
        {
            uint8_t i;

            // See if peer device has been discovered
            for (i = 0; i < centralScanRes; i++)
            {
                if (centralAddrCmp(PeerAddrDef, centralDevList[i].addr))
                    break;
            }

            // Peer device not found
            if (i == centralScanRes)
            {
                logDebug("Device not found...\r\n");
                centralScanRes = 0;
                GAPRole_CentralStartDiscovery(DEFAULT_DISCOVERY_MODE,
                                              DEFAULT_DISCOVERY_ACTIVE_SCAN,
                                              DEFAULT_DISCOVERY_WHITE_LIST);
                logDebug("Discovering...\r\n");
            }

            // Peer device found
            else
            {
                logDebug("Device found...\r\n");
                GAPRole_CentralEstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE,
                                             DEFAULT_LINK_WHITE_LIST,
                                             centralDevList[i].addrType,
                                             centralDevList[i].addr);

                // Start establish link timeout event
                tmos_start_task(centralTaskId, ESTABLISH_LINK_TIMEOUT_EVT, ESTABLISH_LINK_TIMEOUT);
                logDebug("Connecting...\r\n");
            }
        }
        break;

        case GAP_LINK_ESTABLISHED_EVENT:
        {
            tmos_stop_task(centralTaskId, ESTABLISH_LINK_TIMEOUT_EVT);
            if (pEvent->gap.hdr.status == SUCCESS)
            {
                uint8_t connItem;
                // 查询是否有空余连接条目
                for (connItem = 0; connItem < CENTRAL_MAX_CONNECTION; connItem++)
                {
                    if (centralConnList[connItem].connHandle == GAP_CONNHANDLE_INIT)
                        break;
                }
                if (connItem == CENTRAL_MAX_CONNECTION)
                {
                    GAPRole_TerminateLink(pEvent->linkCmpl.connectionHandle);
                    logDebug("Connection max...\r\n");
                }
                else
                {
                    centralConnList[connItem].state      = BLE_STATE_CONNECTED;
                    centralConnList[connItem].connHandle = pEvent->linkCmpl.connectionHandle;

                    logDebug("Conn %x - Int %x \r\n", pEvent->linkCmpl.connectionHandle, pEvent->linkCmpl.connInterval);

                    //  连接0
                    if (connItem == CONNECT0_ITEM)
                    {
                        centralConnList[connItem].procedureInProgress = TRUE;

                        // Initiate service discovery
                        tmos_start_task(centralConnList[connItem].taskID, START_SVC_DISCOVERY_EVT, DEFAULT_SVC_DISCOVERY_DELAY);

                        // Initiate connect parameter update
                        tmos_start_task(centralConnList[connItem].taskID, START_PARAM_UPDATE_EVT, DEFAULT_PARAM_UPDATE_DELAY);

                        // Start RSSI polling
                        tmos_start_task(centralConnList[connItem].taskID, START_READ_RSSI_EVT, DEFAULT_RSSI_PERIOD);
                    }

                    //  连接1
                    else if (connItem == CONNECT1_ITEM)
                    {
                    }

                    //  连接2
                    //                    else if(connItem == CONNECT2_ITEM)
                    //                    {
                    //                    }

                    logDebug("Connected...\r\n");

                    // See if need discover again
                    for (connItem = 0; connItem < CENTRAL_MAX_CONNECTION; connItem++)
                    {
                        if (centralConnList[connItem].connHandle == GAP_CONNHANDLE_INIT)
                            break;
                    }
                    if (connItem < CENTRAL_MAX_CONNECTION)
                    {
                        logDebug("Discovering...\r\n");
                        centralScanRes = 0;
                        GAPRole_CentralStartDiscovery(DEFAULT_DISCOVERY_MODE,
                                                      DEFAULT_DISCOVERY_ACTIVE_SCAN,
                                                      DEFAULT_DISCOVERY_WHITE_LIST);
                    }
                }
            }
            else
            {
                logDebug("Connect Failed...Reason:%X\r\n", pEvent->gap.hdr.status);
                logDebug("Discovering...\r\n");
                centralScanRes = 0;
                GAPRole_CentralStartDiscovery(DEFAULT_DISCOVERY_MODE,
                                              DEFAULT_DISCOVERY_ACTIVE_SCAN,
                                              DEFAULT_DISCOVERY_WHITE_LIST);
            }
        }
        break;

        case GAP_LINK_TERMINATED_EVENT:
        {
            uint8_t connItem;
            for (connItem = 0; connItem < CENTRAL_MAX_CONNECTION; connItem++)
            {
                if (centralConnList[connItem].connHandle == pEvent->linkTerminate.connectionHandle)
                    break;
            }
            if (connItem == CENTRAL_MAX_CONNECTION)
            {
                // Should not go there
            }
            logDebug("  %x  Disconnected...Reason:%x\r\n", centralConnList[connItem].connHandle, pEvent->linkTerminate.reason);
            centralConnList[connItem].state               = BLE_STATE_IDLE;
            centralConnList[connItem].connHandle          = GAP_CONNHANDLE_INIT;
            centralConnList[connItem].discState           = BLE_DISC_STATE_IDLE;
            centralConnList[connItem].charHdl             = 0;
            centralConnList[connItem].procedureInProgress = FALSE;
            centralScanRes                                = 0;

            tmos_stop_task(centralConnList[connItem].taskID, START_READ_RSSI_EVT);

            logDebug("Discovering...\r\n");
            GAPRole_CentralStartDiscovery(DEFAULT_DISCOVERY_MODE,
                                          DEFAULT_DISCOVERY_ACTIVE_SCAN,
                                          DEFAULT_DISCOVERY_WHITE_LIST);
        }
        break;

        case GAP_LINK_PARAM_UPDATE_EVENT:
        {
            logDebug("Update %x - Int %x \r\n", pEvent->linkUpdate.connectionHandle, pEvent->linkUpdate.connInterval);
        }
        break;

        default:
            break;
    }
}

/*********************************************************************
 * @fn      pairStateCB
 *
 * @brief   Pairing state callback.
 *
 * @return  none
 */
static void centralPairStateCB(uint16_t connHandle, uint8_t state, uint8_t status)
{
    if (state == GAPBOND_PAIRING_STATE_STARTED)
    {
        logDebug("Connection %04x - Pairing started:%d\r\n", connHandle, status);
    }
    else if (state == GAPBOND_PAIRING_STATE_COMPLETE)
    {
        if (status == SUCCESS)
        {
            logDebug("Connection %04x - Pairing success\r\n", connHandle);
        }
        else
        {
            logDebug("Connection %04x - Pairing fail\r\n", connHandle);
        }
    }
    else if (state == GAPBOND_PAIRING_STATE_BONDED)
    {
        if (status == SUCCESS)
        {
            logDebug("Connection %04x - Bonding success\r\n", connHandle);
        }
    }
    else if (state == GAPBOND_PAIRING_STATE_BOND_SAVED)
    {
        if (status == SUCCESS)
        {
            logDebug("Connection %04x - Bond save success\r\n", connHandle);
        }
        else
        {
            logDebug("Connection %04x - Bond save failed: %d\r\n", connHandle, status);
        }
    }
}

/*********************************************************************
 * @fn      centralPasscodeCB
 *
 * @brief   Passcode callback.
 *
 * @return  none
 */
static void centralPasscodeCB(uint8_t *deviceAddr, uint16_t connectionHandle,
                              uint8_t uiInputs, uint8_t uiOutputs)
{
    uint32_t passcode;

    // Create random passcode
    passcode = tmos_rand();
    passcode %= 1000000;
    // Display passcode to user
    if (uiOutputs != 0)
    {
        logDebug("Passcode:%06d\r\n", (int)passcode);
    }
    // Send passcode response
    GAPBondMgr_PasscodeRsp(connectionHandle, SUCCESS, passcode);
}

/*********************************************************************
 * @fn      centralConnIistStartDiscovery_0
 *
 * @brief   Start connection 0 service discovery.
 *
 * @return  none
 */
static void centralConnIistStartDiscovery_0(void)
{
    uint8_t uuid[ATT_BT_UUID_SIZE] = {LO_UINT16(SIMPLEPROFILE_SERV_UUID),
                                      HI_UINT16(SIMPLEPROFILE_SERV_UUID)};

    // Initialize cached handles
    centralConnList[CONNECT0_ITEM].svcStartHdl = centralConnList[CONNECT0_ITEM].svcEndHdl = centralConnList[CONNECT0_ITEM].charHdl = 0;

    centralConnList[CONNECT0_ITEM].discState = BLE_DISC_STATE_SVC;

    // Discovery simple BLE service
    GATT_DiscPrimaryServiceByUUID(centralConnList[CONNECT0_ITEM].connHandle,
                                  uuid,
                                  ATT_BT_UUID_SIZE,
                                  centralTaskId);
}

/*********************************************************************
 * @fn      centralGATTDiscoveryEvent
 *
 * @brief   Process GATT discovery event
 *
 * @return  none
 */
static void centralGATTDiscoveryEvent(uint8_t connItem, gattMsgEvent_t *pMsg)
{
    attReadByTypeReq_t req;
    //  连接0的枚举
    if (connItem == CONNECT0_ITEM)
    {
        if (centralConnList[connItem].discState == BLE_DISC_STATE_SVC)
        {
            // Service found, store handles
            if (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
                pMsg->msg.findByTypeValueRsp.numInfo > 0)
            {
                centralConnList[connItem].svcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
                centralConnList[connItem].svcEndHdl   = ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);

                // Display Profile Service handle range
                logDebug("Found Profile Service handle : %x ~ %x \r\n", centralConnList[connItem].svcStartHdl, centralConnList[connItem].svcEndHdl);
#if 0
                for (uint16_t i = 0; i < pMsg->msg.readByGrpTypeRsp.numGrps; i++)
                {
                    // uuid
                    printf("uuid = %x", BUILD_UINT16(
                                            pMsg->msg.readByGrpTypeRsp.pDataList[pMsg->msg.readByGrpTypeRsp.len * i + 4],
                                            pMsg->msg.readByGrpTypeRsp.pDataList[pMsg->msg.readByGrpTypeRsp.len * i + 5]));

                    // Primary Service UUID Length
                    printf("%02d bit x", pMsg->msg.readByGrpTypeRsp.len - 4);

                    // printf("att len = %d\n", pMsg->msg.readByGrpTypeRsp.len);
                    printf("start handle:%04x", BUILD_UINT16(
                                                    pMsg->msg.readByGrpTypeRsp.pDataList[pMsg->msg.readByGrpTypeRsp.len * i],
                                                    pMsg->msg.readByGrpTypeRsp.pDataList[pMsg->msg.readByGrpTypeRsp.len * i + 1]));
                    // Attribute End Group Handle
                    printf("end handle:%04x\r\n", BUILD_UINT16(
                                                      pMsg->msg.readByGrpTypeRsp.pDataList[pMsg->msg.readByGrpTypeRsp.len * i + 2],
                                                      pMsg->msg.readByGrpTypeRsp.pDataList[pMsg->msg.readByGrpTypeRsp.len * i + 3]));
                }
#endif
            }
            // If procedure complete
            if ((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
                 pMsg->hdr.status == bleProcedureComplete) ||
                (pMsg->method == ATT_ERROR_RSP))
            {
                // Discover characteristic
                centralConnList[connItem].discState = BLE_DISC_STATE_CHAR;
                uint8_t ret                         = GATT_DiscAllChars(centralConnList[connItem].connHandle, 0x01, 0xFFFF, centralTaskId);
                logDebug("GATT_DiscAllChars:%02x\r\n", ret);
            }
        }
        else if (centralConnList[connItem].discState == BLE_DISC_STATE_CHAR)
        {
            // Characteristic found, store handle
            if (pMsg->method == ATT_READ_BY_TYPE_RSP &&
                pMsg->msg.readByTypeRsp.numPairs > 0)
            {
                for (unsigned char i = 0; i < pMsg->msg.readByTypeRsp.numPairs; i++)
                {
                    // characteristic properties
                    uint8_t char_properties    = pMsg->msg.readByTypeRsp.pDataList[pMsg->msg.readByTypeRsp.len * i + 2];
                    uint16_t char_value_handle = BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[pMsg->msg.readByTypeRsp.len * i + 3],
                                                              pMsg->msg.readByTypeRsp.pDataList[pMsg->msg.readByTypeRsp.len * i + 4]);
                    // characteristic uuid length
                    uint8_t char_uuid_length = pMsg->msg.readByGrpTypeRsp.len - 5;
                    // uuid
                    uint8_t *char_uuid = &(pMsg->msg.readByGrpTypeRsp.pDataList[pMsg->msg.readByGrpTypeRsp.len * i + 5]);
                    logDebug("|-------------------------------------|");
                    logDebug("char_uuid\t:");
                    for (uint8_t i = 0; i < char_uuid_length; i++)
                    {
                        logDebug("%02x ", char_uuid[i]);
                    }
                    logDebug("char_value_handle\t:%04x\r\n", char_value_handle);
                    logDebug("char_uuid_length\t:%02d bit\r\n", char_uuid_length);
                    uint16_t char1uuid = SIMPLEPROFILE_CHAR1_UUID;
                    uint16_t char2uuid = SIMPLEPROFILE_CHAR2_UUID;
                    uint16_t char3uuid = SIMPLEPROFILE_CHAR3_UUID;
                    uint16_t char4uuid = SIMPLEPROFILE_CHAR4_UUID;
                    if (tmos_memcmp(char_uuid, &char1uuid, 2))
                    {
                        if (char_properties & (GATT_PROP_WRITE | GATT_PROP_WRITE_NO_RSP))
                        {
                            centralConnList[connItem].charHdl = char_value_handle;
                            logDebug("char1 Write handle\t:%04x\r\n", char_value_handle);
                            centralConnList[connItem].procedureInProgress = FALSE;
                            // tmos_start_task(centralConnList[CONNECT0_ITEM].taskID, START_READ_OR_WRITE_EVT, 1600);
                        }
                    }
                    else if (tmos_memcmp(char_uuid, &char2uuid, 2))
                    {
                        if (char_properties & (GATT_PROP_READ))
                        {
                            centralConnList[connItem].charHd2             = char_value_handle;
                            centralConnList[connItem].procedureInProgress = FALSE;
                            logDebug("char2 Write handle\t:%04x\r\n", char_value_handle);
                            // tmos_start_task(centralConnList[CONNECT0_ITEM].taskID, CH2_READ_EVT, 2400);
                        }
                    }
                    else if (tmos_memcmp(char_uuid, &char3uuid, 2))
                    {
                        if (char_properties & (GATT_PROP_WRITE | GATT_PROP_WRITE_NO_RSP))
                        {
                            centralConnList[connItem].charHd3 = char_value_handle;
                            logDebug("char3 Write handle\t:%04x\r\n", char_value_handle);
                            centralConnList[connItem].procedureInProgress = FALSE;
                            tmos_start_task(centralConnList[CONNECT0_ITEM].taskID, CH3_WRITE_EVT, 3200);
                        }
                    }
                    else if (tmos_memcmp(char_uuid, &char4uuid, 2))
                    {
                        if (char_properties & (GATT_PROP_NOTIFY))
                        {
                            centralConnList[connItem].discState           = BLE_DISC_STATE_IDLE;
                            centralConnList[connItem].charHd4             = char_value_handle + 1;
                            centralConnList[connItem].procedureInProgress = FALSE;
                            logDebug("char4 Write handle\t:%04x\r\n", char_value_handle);
                            tmos_start_task(centralConnList[CONNECT0_ITEM].taskID, CH4_NOTI_EVT, 1600);
                        }
                    }
                }
            }
        }
        //  连接1的枚举
        //    else if (connItem == CONNECT1_ITEM)
        //    {

        //    }
        //  连接2的枚举
        //    else if(connItem == CONNECT2_ITEM)
        //    {
        //    }
    }
}
/*********************************************************************
 * @fn      centralAddDeviceInfo
 *
 * @brief   Add a device to the device discovery result list
 *
 * @return  none
 */
static void centralAddDeviceInfo(uint8_t *pAddr, uint8_t addrType)
{
    uint8_t i;

    // If result count not at max
    if (centralScanRes < DEFAULT_MAX_SCAN_RES)
    {
        // Check if device is already in scan results
        for (i = 0; i < centralScanRes; i++)
        {
            if (tmos_memcmp(pAddr, centralDevList[i].addr, B_ADDR_LEN))
            {
                return;
            }
        }
        // Add addr to scan result list
        tmos_memcpy(centralDevList[centralScanRes].addr, pAddr, B_ADDR_LEN);
        centralDevList[centralScanRes].addrType = addrType;
        // Increment scan result count
        centralScanRes++;
        // Display device addr
        logDebug("Device %d - Addr %x %x %x %x %x %x \r\n", centralScanRes,
                 centralDevList[centralScanRes - 1].addr[0],
                 centralDevList[centralScanRes - 1].addr[1],
                 centralDevList[centralScanRes - 1].addr[2],
                 centralDevList[centralScanRes - 1].addr[3],
                 centralDevList[centralScanRes - 1].addr[4],
                 centralDevList[centralScanRes - 1].addr[5]);
    }
}

/*********************************************************************
 * @fn      centralAddrCmp
 *
 * @brief   none
 *
 * @return  none
 */
static uint8_t centralAddrCmp(peerAddrDefItem_t *PeerAddrDef, uint8_t *addr)
{
    uint8_t i;
    for (i = 0; i < CENTRAL_MAX_CONNECTION; i++)
    {
        if (tmos_memcmp(PeerAddrDef[i].peerAddr, addr, B_ADDR_LEN))
            break;
    }
    if (i == CENTRAL_MAX_CONNECTION)
    {
        return FALSE;
    }
    else
    {
        return TRUE;
    }
}

/************************ endfile @ central **************************/

/*用户自定义文件*/
int BSP_Master_Send(centralConnItem_t *centralConnList, uint8_t id, uint8_t *Data, uint8_t Len)
{
    int ret = 0;
    attWriteReq_t req;
    uint8_t res;

    if (centralConnList[id].state == BLE_STATE_CONNECTED) // 检查连接状态是否为连接状态
    {
        if (centralConnList[id].procedureInProgress == FALSE)
        {
            req.cmd    = FALSE;
            req.sig    = FALSE;
            req.handle = centralConnList[id].charHd3;
            req.len    = Len;
            req.pValue = GATT_bm_alloc(centralConnList[id].connHandle, ATT_WRITE_REQ, req.len, NULL, 0);
            if (req.pValue != NULL)
            {
                tmos_memcpy(req.pValue, Data, Len);
                res = GATT_WriteCharValue(centralConnList[id].connHandle, &req, centralTaskId);
                if (res == SUCCESS)
                {
                    logDebug("\n Master Write ok");
                    centralConnList[id].procedureInProgress == FALSE;
                    ret = 0;
                }
                else
                {
                    logDebug("\n Master Write faild= %x", res);
                    GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);
                    ret = 1;
                }
            }
            else
            {
                logDebug("\n alloc Faild");
                ret = 2;
            }
        }
        ret = 3;
    }
    ret = 4;
    return ret;
}

int BSP_Master_Receive_Data(uint8_t task_id, uint8_t *data, uint16_t len)
{
    int ret              = 0;
    uint16_t index       = 0;
    uint8_t data_buf[64] = {0};
    // 解析接收到的数据帧，先寻找AA开头，然后再找AA下一个字节，其代表命令，然后找到代表长度的值的长度的下一位，其为校验码，校验码后为结束码0x55，
    // 如果数据正确，则提取数据，不正确，则不处理
    if (len < 4)
    { // 至少需要 4 个字节：起始码、长度、校验码、结束码
        logError("BT 数据帧长度不足");
        logHexDumpAll(data, len);
        return 1;
    }
    while (index < len && data[index] != 0xAA) // 寻找起始码 0xAA
    {
        index++;
    }
    if (index >= len - 3) // 不够空间容纳长度、校验码和结束码
    {
        logError("BT 数据帧起始码错误");
        logHexDumpAll(data, len);
        return 2;
    }

    uint16_t datalength = data[index + 2]; // 读取数据长度
    if (index + 3 + datalength + 1 >= len) // 检查数据长度是否合理 数据长度 + 校验码 + 结束码
    {

        logError("BT 数据帧长度错误");
        logHexDumpAll(data, len);
        return 3; //
    }

    uint8_t rx_sum         = data[index + 3 + datalength];            // 读取校验码
    uint8_t calculated_sum = _CheckSum(&data[index], datalength + 3); // 计算校验码

    if (rx_sum != calculated_sum)
    {
        logError("BT 数据帧校验码错误 rx_sum = %02X, calculated_sum = %02X", rx_sum, calculated_sum);
        logHexDumpAll(data, len);
        return 4;
    }

    if (data[index + 3 + datalength + 1] != 0x55) // 检查结束码
    {
        logError("BT 数据帧结束码错误");
        logHexDumpAll(data, len);

        return 5;
    }
    logDebug("BT 数据帧校验通过");

    // //有效数据长度
    size_t data_len = (datalength + 5);
    if (data[index + 1] == kCmdCfg) // 0x01 代表了其是控制阀门响应
    {
        logDebug("BT 控制阀门响应包");
        logHexDumpAll(&data[index], len);
    }
    else if (data[index + 1] == kCmdData) // 这个是代表了其是心跳数据包
    {
        logDebug("BT 心跳数据包");
        logHexDumpAll(&data[index], len);
        valve_list.valve_num                    = task_id + 1;
        valve_list.valve_data[task_id].valve_id = data[index + 4];
        // tmos_memcpy(valve_list.valve_data[task_id].valve_mac, &data[index + 5], 6); //将数据提取到结构体中
    }
    // //有效数据长度
    // size_t data_len = (datalength + 5);
    // //到这一步说明数据没问题，将接收到的数据通过中心任务发送出去
    // uint8_t *p_data;
    // p_data = tmos_msg_allocate(data_len);
    // if (p_data)
    // {
    //     tmos_memcpy(p_data, data, data_len);
    //     tmos_msg_send(BtRxTaskId, p_data);
    //     tmos_start_task(BtRxTaskId, SYS_EVENT_MSG, 0);
    // }
    return ret;
}
