⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hci.c

📁 蓝牙协议源代码 bluetooth stack for lwip
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
 * Copyright (c) 2003 EISLAB, Lulea University of Technology.
 * All rights reserved. 
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 * OF SUCH DAMAGE.
 *
 * This file is part of the lwBT Bluetooth stack.
 * 
 * Author: Conny Ohult <conny@sm.luth.se>
 *
 */

/*-----------------------------------------------------------------------------------*/
/* hci.c
 *
 * Implementation of the Host Controller Interface (HCI). A command interface to the
 * baseband controller and link manager, and gives access to hardware status and 
 * control registers.
 *
 */
/*-----------------------------------------------------------------------------------*/

#include "lwbtopts.h"
#include "phybusif.h"
#include "netif/lwbt/hci.h"
#include "netif/lwbt/l2cap.h"
#include "netif/lwbt/lwbt_memp.h"
#include "lwip/debug.h"

/* The HCI LINK lists. */
struct hci_link *hci_active_links;  /* List of all active HCI LINKs */
struct hci_link *hci_tmp_link;

struct hci_pcb *pcb;

/*-----------------------------------------------------------------------------------*/
/* 
 * hci_init():
 *
 * Initializes the HCI layer.
 */
/*-----------------------------------------------------------------------------------*/
err_t
hci_init(void)
{
  if((pcb = lwbt_memp_malloc(MEMP_HCI_PCB)) == NULL) {
    LWIP_DEBUGF(HCI_DEBUG, ("hci_init: Could not allocate memory for pcb\n"));
    return ERR_MEM;
  }
  memset(pcb, 0, sizeof(struct hci_pcb));

  /* Clear globals */
  hci_active_links = NULL;
  hci_tmp_link = NULL;
  return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
/* 
 * hci_new():
 *
 * Creates a new HCI link control block
 */
/*-----------------------------------------------------------------------------------*/
struct hci_link *
hci_new(void)
{
  struct hci_link *link;

  link = lwbt_memp_malloc(MEMP_HCI_LINK);
  if(link != NULL) {
    memset(link, 0, sizeof(struct hci_link));
    return link;
  }
  LWIP_DEBUGF(HCI_DEBUG, ("hci_new: Could not allocate memory for link\n"));
  return NULL;
}
/*-----------------------------------------------------------------------------------*/
/* 
 * hci_close():
 *
 * Close the link control block.
 */
/*-----------------------------------------------------------------------------------*/
err_t
hci_close(struct hci_link *link)
{ 
#if RFCOMM_FLOW_QUEUEING
  if(link->p != NULL) {
    pbuf_free(link->p);
  }
#endif
  HCI_RMV(&(hci_active_links), link);
  lwbt_memp_free(MEMP_HCI_LINK, link);
  link = NULL;
  return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
/* 
 * hci_reset_all():
 *
 * Closes all active link control blocks.
 */
/*-----------------------------------------------------------------------------------*/
void
hci_reset_all(void)
{ 
  struct hci_link *link, *tlink;
  struct hci_inq_res *ires, *tires;

  for(link = hci_active_links; link != NULL;) {
    tlink = link->next;
    hci_close(link);
    link = tlink;
  }
  hci_active_links = NULL;

  for(ires = pcb->ires; ires != NULL;) {
    tires = ires->next;
    lwbt_memp_free(MEMP_HCI_INQ, ires);
    ires = tires;
  }
  lwbt_memp_free(MEMP_HCI_PCB, pcb);
  
  hci_init();
}
/*-----------------------------------------------------------------------------------*/
/* 
 * hci_arg():
 *
 * Used to specify the argument that should be passed callback
 * functions.
 */
/*-----------------------------------------------------------------------------------*/
void
hci_arg(void *arg)
{
  pcb->callback_arg = arg;
}
/*-----------------------------------------------------------------------------------*/
/* 
 * hci_cmd_complete():
 *
 * Used to specify the function that should be called when HCI has received a 
 * command complete event.
 */
/*-----------------------------------------------------------------------------------*/
void
hci_cmd_complete(err_t (* cmd_complete)(void *arg, struct hci_pcb *pcb, u8_t ogf, 
					u8_t ocf, u8_t result)) 
{
  pcb->cmd_complete = cmd_complete;
}
/*-----------------------------------------------------------------------------------*/
/* 
 * hci_pin_req():
 *
 * Used to specify the function that should be called when HCI has received a 
 * PIN code request event.
 */
/*-----------------------------------------------------------------------------------*/
void
hci_pin_req(err_t (* pin_req)(void *arg, struct bd_addr *bdaddr))
{
  pcb->pin_req = pin_req;
}
/*-----------------------------------------------------------------------------------*/
/* 
 * hci_link_key_not():
 *
 * Used to specify the function that should be called when HCI has received a 
 * link key notification event.
 */
/*-----------------------------------------------------------------------------------*/
void 
hci_link_key_not(err_t (* link_key_not)(void *arg, struct bd_addr *bdaddr, u8_t *key))
{
  pcb->link_key_not = link_key_not;
}
/*-----------------------------------------------------------------------------------*/
/* 
 * hci_connection_complete():
 *
 * Used to specify the function that should be called when HCI has received a 
 * connection complete event.
 */
/*-----------------------------------------------------------------------------------*/
void 
hci_connection_complete(err_t (* conn_complete)(void *arg, struct bd_addr *bdaddr))
{
  pcb->conn_complete = conn_complete;
}
/*-----------------------------------------------------------------------------------*/
/* 
 * hci_wlp_complete():
 *
 * Used to specify the function that should be called when HCI has received a 
 * successful write link policy complete event.
 */
/*-----------------------------------------------------------------------------------*/
void 
hci_wlp_complete(err_t (* wlp_complete)(void *arg, struct bd_addr *bdaddr))
{
  pcb->wlp_complete = wlp_complete;
}
/*-----------------------------------------------------------------------------------*/
/* 
 * hci_get_link():
 *
 * Used to get the link structure for that represents an ACL connection.
 */
/*-----------------------------------------------------------------------------------*/
struct hci_link *
hci_get_link(struct bd_addr *bdaddr)
{
  struct hci_link *link;

  for(link = hci_active_links; link != NULL; link = link->next) {
    if(bd_addr_cmp(&(link->bdaddr), bdaddr)) {
      break;
    }
  }
  return link;
}
/*-----------------------------------------------------------------------------------*/
/* 
 * hci_acl_input():
 *
 * Called by the physical bus interface. Handles host controller to host flow control,
 * finds a bluetooth address that correspond to the connection handle and forward the
 * packet to the L2CAP layer.
 */
/*-----------------------------------------------------------------------------------*/
void
hci_acl_input(struct pbuf *p)
{
  struct hci_acl_hdr *aclhdr;
  struct hci_link *link;
  u16_t conhdl;

  pbuf_header(p, HCI_ACL_HDR_LEN);
  aclhdr = p->payload;
  pbuf_header(p, -HCI_ACL_HDR_LEN);

  conhdl = aclhdr->conhdl_pb_bc & 0x0FFF; /* Get the connection handle from the first
						   12 bits */
  if(pcb->flow) {
    //TODO: XXX??? DO WE SAVE NUMACL PACKETS COMPLETED IN LINKS LIST?? SHOULD WE CALL 
    //hci_host_num_comp_packets from the main loop when no data has been received from the 
    //serial port???
    --pcb->host_num_acl;
    if(pcb->host_num_acl == 0) {
      hci_host_num_comp_packets(conhdl, HCI_HOST_MAX_NUM_ACL);
      pcb->host_num_acl = HCI_HOST_MAX_NUM_ACL;
    }
  }

  for(link = hci_active_links; link != NULL; link = link->next) {
    if(link->conhdl == conhdl) {
      break;
    }
  }
  
  if(link != NULL) {
    if(aclhdr->len) {
      LWIP_DEBUGF(HCI_DEBUG, ("hci_acl_input: Forward ACL packet to higher layer p->tot_len = %d\n", p->tot_len));
      l2cap_input(p, &(link->bdaddr));
    } else {
      pbuf_free(p); /* If length of ACL packet is zero, we silently discard it */
    }
  } else {
    pbuf_free(p); /* If no acitve ACL link was found, we silently discard the packet */
  }
}
/*-----------------------------------------------------------------------------------*/
#if HCI_EV_DEBUG
u8_t *
hci_get_error_code(u8_t code) {
  switch(code) {
  case HCI_SUCCESS:
    return("Success");
  case HCI_UNKNOWN_HCI_COMMAND:
    return("Unknown HCI Command");
  case HCI_NO_CONNECTION:
    return("No Connection");
  case HCI_HW_FAILURE:
    return("Hardware Failure");
  case HCI_PAGE_TIMEOUT:
    return("Page Timeout");
  case HCI_AUTHENTICATION_FAILURE:
    return("Authentication Failure");
  case HCI_KEY_MISSING:
    return("Key Missing");
  case HCI_MEMORY_FULL:
    return("Memory Full");
  case HCI_CONN_TIMEOUT:
    return("Connection Timeout");
  case HCI_MAX_NUMBER_OF_CONNECTIONS:
    return("Max Number Of Connections");
  case HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE:
    return("Max Number Of SCO Connections To A Device");
  case HCI_ACL_CONNECTION_EXISTS:
    return("ACL connection already exists");
  case HCI_COMMAND_DISSALLOWED:
    return("Command Disallowed");
  case HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES:
    return("Host Rejected due to limited resources");
  case HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS:
    return("Host Rejected due to security reasons");
  case HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE:
    return("Host Rejected due to remote device is only a personal device");
  case HCI_HOST_TIMEOUT:
    return("Host Timeout");
  case HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE:
    return("Unsupported Feature or Parameter Value");
  case HCI_INVALID_HCI_COMMAND_PARAMETERS:
    return("Invalid HCI Command Parameters");
  case HCI_OTHER_END_TERMINATED_CONN_USER_ENDED:
    return("Other End Terminated Connection: User Ended Connection");
  case HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES:
    return("Other End Terminated Connection: Low Resources");
  case HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF:
    return("Other End Terminated Connection: About to Power Off");
  case HCI_CONN_TERMINATED_BY_LOCAL_HOST:
    return("Connection Terminated by Local Host");
  case HCI_REPETED_ATTEMPTS:
    return("Repeated Attempts");
  case HCI_PAIRING_NOT_ALLOWED:
    return("Pairing Not Allowed");
  case HCI_UNKNOWN_LMP_PDU:
    return("Unknown LMP PDU");
  case HCI_UNSUPPORTED_REMOTE_FEATURE:
    return("Unsupported Remote Feature");
  case HCI_SCO_OFFSET_REJECTED:
    return("SCO Offset Rejected");
  case HCI_SCO_INTERVAL_REJECTED:
    return("SCO Interval Rejected");
  case HCI_SCO_AIR_MODE_REJECTED:
    return("SCO Air Mode Rejected");
  case HCI_INVALID_LMP_PARAMETERS:
    return("Invalid LMP Parameters");
  case HCI_UNSPECIFIED_ERROR:
    return("Unspecified Error");
  case HCI_UNSUPPORTED_LMP_PARAMETER_VALUE:
    return("Unsupported LMP Parameter Value");
  case HCI_ROLE_CHANGE_NOT_ALLOWED:
    return("Role Change Not Allowed");
  case HCI_LMP_RESPONSE_TIMEOUT:
    return("LMP Response Timeout");
  case HCI_LMP_ERROR_TRANSACTION_COLLISION:
    return("LMP Error Transaction Collision");
  case HCI_LMP_PDU_NOT_ALLOWED:
    return("LMP PDU Not Allowed");
  case HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE:
    return("Encryption Mode Not Acceptable");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -