/******************************************************************************* ** ** Function gatt_send_queue_write_cancel ** ** Description send queue write cancel ** ** Returns void. ** *******************************************************************************/ void gatt_send_queue_write_cancel (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, tGATT_EXEC_FLAG flag) { UINT8 rt ; GATT_TRACE_DEBUG("gatt_send_queue_write_cancel "); rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, GATT_REQ_EXEC_WRITE, (tGATT_CL_MSG *)&flag); if (rt != GATT_SUCCESS) { gatt_end_operation(p_clcb, rt, NULL); } }
/******************************************************************************* ** ** Function gatt_act_discovery ** ** Description GATT discovery operation. ** ** Returns void. ** *******************************************************************************/ void gatt_act_discovery(tGATT_CLCB *p_clcb) { UINT8 op_code = disc_type_to_att_opcode[p_clcb->op_subtype]; tGATT_CL_MSG cl_req; tGATT_STATUS st; if (p_clcb->s_handle <= p_clcb->e_handle && p_clcb->s_handle != 0) { memset(&cl_req, 0, sizeof(tGATT_CL_MSG)); cl_req.browse.s_handle = p_clcb->s_handle; cl_req.browse.e_handle = p_clcb->e_handle; if (disc_type_to_uuid[p_clcb->op_subtype] != 0) { cl_req.browse.uuid.len = 2; cl_req.browse.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype]; } if (p_clcb->op_subtype == GATT_DISC_SRVC_BY_UUID) /* fill in the FindByTypeValue request info*/ { cl_req.find_type_value.uuid.len = 2; cl_req.find_type_value.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype]; cl_req.find_type_value.s_handle = p_clcb->s_handle; cl_req.find_type_value.e_handle = p_clcb->e_handle; cl_req.find_type_value.value_len = p_clcb->uuid.len; /* if service type is 32 bits UUID, convert it now */ if (p_clcb->uuid.len == LEN_UUID_32) { cl_req.find_type_value.value_len = LEN_UUID_128; gatt_convert_uuid32_to_uuid128(cl_req.find_type_value.value, p_clcb->uuid.uu.uuid32); } else memcpy (cl_req.find_type_value.value, &p_clcb->uuid.uu, p_clcb->uuid.len); } st = attp_send_cl_msg(p_clcb->p_tcb, p_clcb->clcb_idx, op_code, &cl_req); if (st != GATT_SUCCESS && st != GATT_CMD_STARTED) { gatt_end_operation(p_clcb, GATT_ERROR, NULL); } } else /* end of handle range */ gatt_end_operation(p_clcb, GATT_SUCCESS, NULL); }
/******************************************************************************* ** ** Function gatt_act_discovery ** ** Description GATT discovery operation. ** ** Returns void. ** *******************************************************************************/ void gatt_act_discovery(tGATT_CLCB *p_clcb) { UINT8 op_code = disc_type_to_att_opcode[p_clcb->op_subtype]; tGATT_CL_MSG cl_req; if (p_clcb->s_handle <= p_clcb->e_handle && p_clcb->s_handle != 0) { memset(&cl_req, 0, sizeof(tGATT_CL_MSG)); cl_req.browse.s_handle = p_clcb->s_handle; cl_req.browse.e_handle = p_clcb->e_handle; if (disc_type_to_uuid[p_clcb->op_subtype] != 0) { cl_req.browse.uuid.len = 2; cl_req.browse.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype]; } if (p_clcb->op_subtype == GATT_DISC_SRVC_BY_UUID) /* fill in the FindByTypeValue request info*/ { cl_req.find_type_value.uuid.len = 2; cl_req.find_type_value.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype]; cl_req.find_type_value.s_handle = p_clcb->s_handle; cl_req.find_type_value.e_handle = p_clcb->e_handle; cl_req.find_type_value.value_len = p_clcb->uuid.len; memcpy (cl_req.find_type_value.value, &p_clcb->uuid.uu, p_clcb->uuid.len); } if (attp_send_cl_msg(p_clcb->p_tcb, p_clcb->clcb_idx, op_code, &cl_req) != GATT_SUCCESS) { gatt_end_operation(p_clcb, GATT_ERROR, NULL); } } else /* end of handle range */ gatt_end_operation(p_clcb, GATT_SUCCESS, NULL); }
/******************************************************************************* ** ** Function gatt_process_notification ** ** Description This function is called to handle the handle value indication ** or handle value notification. ** ** ** Returns void ** *******************************************************************************/ void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code, UINT16 len, UINT8 *p_data) { tGATT_VALUE value = {0}; tGATT_REG *p_reg; UINT16 conn_id; tGATT_STATUS encrypt_status; UINT8 *p = p_data, i, event = (op_code == GATT_HANDLE_VALUE_NOTIF) ? GATTC_OPTYPE_NOTIFICATION : GATTC_OPTYPE_INDICATION; GATT_TRACE_DEBUG("gatt_process_notification "); if (len < GATT_NOTIFICATION_MIN_LEN) { GATT_TRACE_ERROR("illegal notification PDU length, discard"); return; } STREAM_TO_UINT16 (value.handle, p); value.len = len - 2; memcpy (value.value, p, value.len); if (!GATT_HANDLE_IS_VALID(value.handle)) { /* illegal handle, send ack now */ if (op_code == GATT_HANDLE_VALUE_IND) { attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL); } return; } if (event == GATTC_OPTYPE_INDICATION) { if (p_tcb->ind_count) { /* this is an error case that receiving an indication but we still has an indication not being acked yet. For now, just log the error reset the counter. Later we need to disconnect the link unconditionally. */ GATT_TRACE_ERROR("gatt_process_notification rcv Ind. but ind_count=%d (will reset ind_count)", p_tcb->ind_count); } p_tcb->ind_count = 0; } /* should notify all registered client with the handle value notificaion/indication Note: need to do the indication count and start timer first then do callback */ for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb && (event == GATTC_OPTYPE_INDICATION)) { p_tcb->ind_count++; } } if (event == GATTC_OPTYPE_INDICATION) { /* start a timer for app confirmation */ if (p_tcb->ind_count > 0) { gatt_start_ind_ack_timer(p_tcb); } else { /* no app to indicate, or invalid handle */ attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL); } } encrypt_status = gatt_get_link_encrypt_status(p_tcb); for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb) { conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if); (*p_reg->app_cb.p_cmpl_cb) (conn_id, event, encrypt_status, (tGATT_CL_COMPLETE *)&value); } } }
/******************************************************************************* ** ** Function gatt_act_read ** ** Description GATT read operation. ** ** Returns void. ** *******************************************************************************/ void gatt_act_read (tGATT_CLCB *p_clcb, UINT16 offset) { tGATT_TCB *p_tcb = p_clcb->p_tcb; UINT8 rt = GATT_INTERNAL_ERROR; tGATT_CL_MSG msg; UINT8 op_code = 0; memset (&msg, 0, sizeof(tGATT_CL_MSG)); switch (p_clcb->op_subtype) { case GATT_READ_CHAR_VALUE: case GATT_READ_BY_TYPE: op_code = GATT_REQ_READ_BY_TYPE; msg.browse.s_handle = p_clcb->s_handle; msg.browse.e_handle = p_clcb->e_handle; if (p_clcb->op_subtype == GATT_READ_BY_TYPE) { memcpy(&msg.browse.uuid, &p_clcb->uuid, sizeof(tBT_UUID)); } else { msg.browse.uuid.len = LEN_UUID_16; msg.browse.uuid.uu.uuid16 = GATT_UUID_CHAR_DECLARE; } break; case GATT_READ_CHAR_VALUE_HDL: case GATT_READ_BY_HANDLE: if (!p_clcb->counter) { op_code = GATT_REQ_READ; msg.handle = p_clcb->s_handle; } else { if (!p_clcb->first_read_blob_after_read) { p_clcb->first_read_blob_after_read = TRUE; } else { p_clcb->first_read_blob_after_read = FALSE; } GATT_TRACE_DEBUG("gatt_act_read first_read_blob_after_read=%d", p_clcb->first_read_blob_after_read); op_code = GATT_REQ_READ_BLOB; msg.read_blob.offset = offset; msg.read_blob.handle = p_clcb->s_handle; } p_clcb->op_subtype &= ~ 0x80; break; case GATT_READ_PARTIAL: op_code = GATT_REQ_READ_BLOB; msg.read_blob.handle = p_clcb->s_handle; msg.read_blob.offset = offset; break; case GATT_READ_MULTIPLE: op_code = GATT_REQ_READ_MULTI; memcpy (&msg.read_multi, p_clcb->p_attr_buf, sizeof(tGATT_READ_MULTI)); break; case GATT_READ_INC_SRV_UUID128: op_code = GATT_REQ_READ; msg.handle = p_clcb->s_handle; p_clcb->op_subtype &= ~ 0x90; break; default: GATT_TRACE_ERROR("Unknown read type: %d", p_clcb->op_subtype); break; } if (op_code != 0) { rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, op_code, &msg); } if ( op_code == 0 || (rt != GATT_SUCCESS && rt != GATT_CMD_STARTED)) { gatt_end_operation(p_clcb, rt, NULL); } }