/********************************************************************* * INCLUDES */ #include "CONFIG.h" #include "gattprofile.h" #include "multiCentral.h" #include "bsp_uart.h" #include "log.h" #include "bsp_flash.h" #include "bsp_valve.h" #undef LOG_ENABLE #define LOG_ENABLE 1 #define MASTER_START_EVT (0X01 << 0) #define MASTER_CONNECT_EVT (0X01 << 1) #define MASTER_DISCONN_EVT (0X01 << 2) #define MASTER_DETECT_EVT (0X01 << 3) uint8_t MasterCtrTaskId; /********************************************************************* * 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 1 // Scan duration in 0.625ms #define DEFAULT_SCAN_DURATION 1600 * 3 // 2400*0.625 = 1500ms // Connection min interval in 1.25ms #define DEFAULT_MIN_CONNECTION_INTERVAL (80 * 4) // Connection max interval in 1.25ms #define DEFAULT_MAX_CONNECTION_INTERVAL 80 * 5 // Connection supervision timeout in 10ms #define DEFAULT_CONNECTION_TIMEOUT (100 * 3) // 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 TRUE // 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 4800 // Minimum connection interval (units of 1.25ms) #define DEFAULT_UPDATE_MIN_CONN_INTERVAL DEFAULT_MIN_CONNECTION_INTERVAL // Maximum connection interval (units of 1.25ms) #define DEFAULT_UPDATE_MAX_CONN_INTERVAL DEFAULT_MAX_CONNECTION_INTERVAL // Slave latency to use parameter update #define DEFAULT_UPDATE_SLAVE_LATENCY 0 // Supervision timeout value (units of 10ms) #define DEFAULT_UPDATE_CONN_TIMEOUT 100 * 5 // 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 10 // Default parameter update delay in 0.625ms #define DEFAULT_PARAM_UPDATE_DELAY 1600 // 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 1600 * 3 // 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 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 peerAddrDefItem_t PeerAddrDef[CENTRAL_MAX_CONNECTION] = { // {0xb6, 0xb4, 0x8f, 0x10, 0x53, 0x5c}, }; // 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); uint16_t Master_ProcessEvent(uint8_t task_id, uint16_t events); /********************************************************************* * 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); //用户自定义 MasterCtrTaskId = TMOS_ProcessEventRegister(Master_ProcessEvent); tmos_set_event(MasterCtrTaskId, MASTER_START_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, ¢ralBondCB, ¢ralRoleCB); 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) { // logDebug("connect0_ProcessEvent 0x%02x", events); if (events & START_SVC_DISCOVERY_EVT) { // logDebug("START_SVC_DISCOVERY_EVT"); // start service discovery // centralConnIistStartDiscovery_0(); logDebug("发现句柄配置\r\n"); centralConnList[CONNECT0_ITEM].charHdl = 0X23; centralConnList[CONNECT0_ITEM].charHd2 = 0X26; centralConnList[CONNECT0_ITEM].charHd3 = 0x29; centralConnList[CONNECT0_ITEM].charHd4 = 0x2C; centralConnList[CONNECT0_ITEM].procedureInProgress = FALSE; return (events ^ START_SVC_DISCOVERY_EVT); } if (events & START_READ_OR_WRITE_EVT) { logDebug("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 + 1); req.cmd = FALSE; req.sig = FALSE; req.handle = centralConnList[CONNECT0_ITEM].charHd4 + 1; 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: "); 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); centralConnList[connItem].discState = BLE_DISC_STATE_IDLE; } 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) { logDebug("MTU changed: %d, %d\r\n", maxTxOctets, maxRxOctets); // centralConnList[CONNECT0_ITEM].procedureInProgress = FALSE; // tmos_start_task(centralConnList[CONNECT0_ITEM].taskID, CH4_NOTI_EVT, 1600); } /********************************************************************* * @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: { GAPRole_CentralCancelDiscovery(); // logDebug("停止扫描,发起直连\r\n"); // tmos_start_task(MasterCtrTaskId, MASTER_CONNECT_EVT, 800); } break; case GAP_DEVICE_INFO_EVENT: { // Add device to list centralAddDeviceInfo(pEvent->deviceInfo.addr, pEvent->deviceInfo.addrType); } break; case GAP_DEVICE_DISCOVERY_EVENT: { Master_Connect(); 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; // update MTU // attExchangeMTUReq_t req = // { // .clientRxMTU = BLE_BUFF_MAX_LEN - 4, // }; // GATT_ExchangeMTU(pEvent->linkCmpl.connectionHandle, &req, centralTaskId); // 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); } 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; } } } else { logDebug("Connect Failed...Reason:%X\r\n", pEvent->gap.hdr.status); logDebug("Discovering...\r\n"); centralScanRes = 0; } } 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"); } 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; // 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) { logDebug("发现句柄配置\r\n"); centralConnList[connItem].charHdl = 0X23; centralConnList[connItem].charHd2 = 0X26; centralConnList[connItem].charHd3 = 0x29; centralConnList[connItem].charHd4 = 0x2C; centralConnList[connItem].procedureInProgress = FALSE; #if 0 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) { #if 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].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); } } } #endif } } #endif } // 连接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) // 检查连接状态是否为连接状态 { logDebug("BLE_STATE_CONNECTED"); if (centralConnList[id].procedureInProgress == FALSE) { logDebug("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 = TRUE; ret = 0; } else { logError("\n Master Write faild= %x", res); GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ); ret = 1; } } else { logError("\n alloc Faild"); ret = 2; } } else { logError("procedureInProgress"); ret = 3; } } else { logError("没有连接成功"); 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); ret = data_len; if (data[index + 1] == kCmdCloseVavle) // 0x02 代表了其是控制阀门响应 { // logDebug("BT 控制阀门响应包"); if (data[index + datalength + 2] == 1) // 响应数据位 { logInfo("关闭阀门成功"); } else { logError("BT 控制阀门失败"); } } else if (data[index + 1] == kValveCmdRep) // 这个是代表了其是心跳数据包 { logDebug("蓝牙从机心跳数据包:"); logHexDumpAll(data, data_len); } // 到这一步说明数据没问题,将接收到的数据通过中心任务发送出去 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; } void Master_Connect(void) { uint8_t def_mac[6] = {0xFF}; uint8_t cnt = Flash_Get_Valve_Num(); logDebug("cnt:%d\r\n", cnt); // if (cnt == 0) // { // GAPRole_CentralEstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE, // DEFAULT_LINK_WHITE_LIST, // ADDRTYPE_PUBLIC, // def_mac); // tmos_start_task(centralTaskId, ESTABLISH_LINK_TIMEOUT_EVT, ESTABLISH_LINK_TIMEOUT); // // uint8_t mac_addr[6] = {0x93, 0xB4, 0x8F, 0x10, 0x53, 0x5C}; // // logHexDumpAll(mac_addr, 6); // // GAPRole_CentralEstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE, // // DEFAULT_LINK_WHITE_LIST, // // ADDRTYPE_PUBLIC, // // mac_addr); // // tmos_start_task(centralTaskId, ESTABLISH_LINK_TIMEOUT_EVT, ESTABLISH_LINK_TIMEOUT); // return; // } for (uint8_t i = 0; i < cnt; i++) { if (valve_list.valve_data[i].valve_id != 0) { logDebug("valve_id:%d\r\n", valve_list.valve_data[i].valve_id); logHexDumpAll(valve_list.valve_data[i].valve_mac, 6); GAPRole_CentralEstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE, DEFAULT_LINK_WHITE_LIST, ADDRTYPE_PUBLIC, valve_list.valve_data[i].valve_mac); tmos_start_task(centralTaskId, ESTABLISH_LINK_TIMEOUT_EVT, ESTABLISH_LINK_TIMEOUT); logDebug("Connecting...\r\n"); } } } void Master_DisConnect(void) { GAPRole_TerminateLink(centralConnList[0].connHandle); // centralConnList[0].state = BLE_STATE_IDLE; logDebug("主动断开连接\r\n"); } uint16_t Master_ProcessEvent(uint8_t task_id, uint16_t events) { int8_t ret = 0; uint8_t *pMsg; uint8_t master_buf[64] = {0}; if (events & MASTER_START_EVT) { if (centralConnList[0].state != BLE_STATE_CONNECTED) { if (Flash_Get_Valve_Num())//如果有设备,发起连接 { tmos_start_task(task_id, MASTER_CONNECT_EVT, 1600); } } tmos_start_task(task_id, MASTER_DETECT_EVT, 3200); return (events ^ MASTER_START_EVT); } else if(events & MASTER_DETECT_EVT) { if (centralConnList[0].state != BLE_STATE_CONNECTED) { if (Flash_Get_Valve_Num()) { logDebug("有设备,尝试连接\r\n"); tmos_start_task(task_id, MASTER_CONNECT_EVT, 1600); } } tmos_start_task(task_id, MASTER_DETECT_EVT, 3200); return (events ^ MASTER_DETECT_EVT); } else if (events & MASTER_CONNECT_EVT) { if (centralConnList[0].state != BLE_STATE_CONNECTED) { Master_Connect(); } return (events ^ MASTER_CONNECT_EVT); } else if (events & MASTER_DISCONN_EVT) { Master_DisConnect(); return (events ^ MASTER_DISCONN_EVT); } return 0; }