Example #1
0
static inline void cmd_complete(int dev, bdaddr_t *sba, void *ptr)
{
	evt_cmd_complete *evt = ptr;
	switch (evt->opcode) {
	case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY_CANCEL):
		hcid_dbus_inquiry_complete(sba);
		break;
	case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME):
		hcid_dbus_setname_complete(sba);
		break;
	case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE):
		hcid_dbus_setscan_enable_complete(sba);
	};
}
Example #2
0
int fm_send_cmd(int dd, uint16_t ogf, uint16_t ocf, uint8_t plen, void *param)
{
	hci_command_hdr hc;
	int skb_len = HCI_COMMAND_PKT + HCI_COMMAND_HDR_SIZE + plen;
	char skb[skb_len];

	FM_CHRLIB_DBG("Inside %s", __FUNCTION__);

	hc.opcode = htobs(cmd_opcode_pack(ogf, ocf));
	hc.plen= plen;

	skb[0] = HCI_COMMAND_PKT;
	memcpy(&skb[1], &hc, HCI_COMMAND_HDR_SIZE);

	if (plen)
		memcpy(&skb[4], param, plen);

	while (write(dd, skb, skb_len) < 0) {
		if (errno == EAGAIN || errno == EINTR)
			continue;

		FM_CHRLIB_ERR("fm_send_cmd() Write failed (%d)", errno);
		return -1;
	}
	return 0;
}
static void command_complete(uint16_t ogf, uint16_t ocf, int plen, void *data)
{
	uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;
	evt_cmd_complete *cc;
	hci_event_hdr *he;

	/* Packet type */
	*ptr++ = HCI_EVENT_PKT;

	/* Event header */
	he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;

	he->evt  = EVT_CMD_COMPLETE;
	he->plen = EVT_CMD_COMPLETE_SIZE + plen;

	cc = (void *) ptr; ptr += EVT_CMD_COMPLETE_SIZE;

	cc->ncmd = 1;
	cc->opcode = htobs(cmd_opcode_pack(ogf, ocf));

	if (plen) {
		memcpy(ptr, data, plen);
		ptr += plen;
	}

	write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);

	if (write(vdev.fd, buf, ptr - buf) < 0)
		syslog(LOG_ERR, "Can't send event: %s(%d)",
						strerror(errno), errno);
}
static void command_status(uint16_t ogf, uint16_t ocf, uint8_t status)
{
	uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;
	evt_cmd_status *cs;
	hci_event_hdr *he;

	/* Packet type */
	*ptr++ = HCI_EVENT_PKT;

	/* Event header */
	he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;

	he->evt  = EVT_CMD_STATUS;
	he->plen = EVT_CMD_STATUS_SIZE;

	cs = (void *) ptr; ptr += EVT_CMD_STATUS_SIZE;

	cs->status = status;
	cs->ncmd   = 1;
	cs->opcode = htobs(cmd_opcode_pack(ogf, ocf));

	write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);

	if (write(vdev.fd, buf, ptr - buf) < 0)
		syslog(LOG_ERR, "Can't send event: %s(%d)",
						strerror(errno), errno);
}
static void rewrite_bdaddr(unsigned char *buf, int len, bdaddr_t *bdaddr)
{
	hci_event_hdr *eh;
	unsigned char *ptr = buf;
	int type;

	if (!bdaddr)
		return;

	if (!bacmp(bdaddr, BDADDR_ANY))
		return;

	type = *ptr++;

	switch (type) {
	case HCI_EVENT_PKT:
		eh = (hci_event_hdr *) ptr;
		ptr += HCI_EVENT_HDR_SIZE;

		if (eh->evt == EVT_CMD_COMPLETE) {
			evt_cmd_complete *cc = (void *) ptr;

			ptr += EVT_CMD_COMPLETE_SIZE;

			if (cc->opcode == htobs(cmd_opcode_pack(OGF_INFO_PARAM,
						OCF_READ_BD_ADDR))) {
				bacpy((bdaddr_t *) (ptr + 1), bdaddr);
			}
		}
		break;
	}
}
Example #6
0
static inline void cmd_status(int dev, bdaddr_t *sba, void *ptr)
{
	evt_cmd_status *evt = ptr;

	if (evt->status)
		return;

	if (evt->opcode == cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY))
		hcid_dbus_inquiry_start(sba);
}
Example #7
0
void hci_send_cmd(uint16_t ogf, uint16_t ocf, uint8_t plen, void *param)
{
  hci_command_hdr hc;
  
  hc.opcode = htobs(cmd_opcode_pack(ogf, ocf));
  hc.plen= plen;
  
  uint8_t header[HCI_HDR_SIZE + HCI_COMMAND_HDR_SIZE];
  header[0] = HCI_COMMAND_PKT;
  Osal_MemCpy(header+1, &hc, sizeof(hc));
  
  hci_write(header, param, sizeof(header), plen);
}
Example #8
0
int hci_send_req(struct hci_request *r, BOOL async)
{
  uint8_t *ptr;
  uint16_t opcode = htobs(cmd_opcode_pack(r->ogf, r->ocf));
  hci_event_pckt *event_pckt;
  hci_uart_pckt *hci_hdr;
  int to = DEFAULT_TIMEOUT;
  struct timer t;
  tHciDataPacket * hciReadPacket = NULL;
  tListNode hciTempQueue;
  
  list_init_head(&hciTempQueue);
  
  hci_send_cmd(r->ogf, r->ocf, r->clen, r->cparam);
  
  if(async){
    goto done;
  }
  
  /* Minimum timeout is 1. */
  if(to == 0)
    to = 1;
  
  Timer_Set(&t, to);
  
  while(1) {
    evt_cmd_complete *cc;
    evt_cmd_status *cs;
    evt_le_meta_event *me;
    int len;
      
#if ENABLE_MICRO_SLEEP    
    while(1){
      ATOMIC_SECTION_BEGIN();
      if(Timer_Expired(&t)){
        ATOMIC_SECTION_END();
        goto failed;
      }
      if(!HCI_Queue_Empty()){
        ATOMIC_SECTION_END();
        break;
      }
      Enter_Sleep_Mode();
      ATOMIC_SECTION_END();
    }
#else
    while(1){
      if(Timer_Expired(&t)){
        goto failed;
      }
      if(!HCI_Queue_Empty()){
        break;
      }
    }
#endif
    
    /* Extract packet from HCI event queue. */
    Disable_SPI_IRQ();
    list_remove_head(&hciReadPktRxQueue, (tListNode **)&hciReadPacket);    
    
    hci_hdr = (void *)hciReadPacket->dataBuff;
    if(hci_hdr->type != HCI_EVENT_PKT){
      list_insert_tail(&hciTempQueue, (tListNode *)hciReadPacket); // See comment below
      Enable_SPI_IRQ();
      continue;
    }
    
    event_pckt = (void *) (hci_hdr->data);
    
    ptr = hciReadPacket->dataBuff + (1 + HCI_EVENT_HDR_SIZE);
    len = hciReadPacket->data_len - (1 + HCI_EVENT_HDR_SIZE);
    
    switch (event_pckt->evt) {
      
    case EVT_CMD_STATUS:
      cs = (void *) ptr;
      
      if (cs->opcode != opcode)
        goto failed;
      
      if (r->event != EVT_CMD_STATUS) {
        if (cs->status) {
          goto failed;
        }
        break;
      }
      
      r->rlen = MIN(len, r->rlen);
      Osal_MemCpy(r->rparam, ptr, r->rlen);
      goto done;
      
    case EVT_CMD_COMPLETE:
      cc = (void *) ptr;
      
      if (cc->opcode != opcode)
        goto failed;
      
      ptr += EVT_CMD_COMPLETE_SIZE;
      len -= EVT_CMD_COMPLETE_SIZE;
      
      r->rlen = MIN(len, r->rlen);
      Osal_MemCpy(r->rparam, ptr, r->rlen);
      goto done;
      
    case EVT_LE_META_EVENT:
      me = (void *) ptr;
      
      if (me->subevent != r->event)
        break;
      
      len -= 1;
      r->rlen = MIN(len, r->rlen);
      Osal_MemCpy(r->rparam, me->data, r->rlen);
      goto done;
      
    case EVT_HARDWARE_ERROR:            
      goto failed;
      
    default:      
      break;
    }
    
    /* In the meantime there could be other events from the controller.
    In this case, insert the packet in a different queue. These packets will be
    inserted back in the main queue just before exiting from send_req().
    */
    list_insert_tail(&hciTempQueue, (tListNode *)hciReadPacket);
    /* Be sure there is at list one packet in the pool to process the expected event. */
    if(list_is_empty(&hciReadPktPool)){
      pListNode tmp_node;      
      list_remove_head(&hciReadPktRxQueue, &tmp_node);
      list_insert_tail(&hciReadPktPool, tmp_node);      
    }
    
    Enable_SPI_IRQ();
    
  }
  
failed: 
  move_list(&hciReadPktRxQueue, &hciTempQueue);  
  Enable_SPI_IRQ();
  return -1;
  
done:
  // Insert the packet back into the pool.
  list_insert_head(&hciReadPktPool, (tListNode *)hciReadPacket); 
  move_list(&hciReadPktRxQueue, &hciTempQueue);
  
  Enable_SPI_IRQ();
  return 0;
}
Example #9
0
static struct scope_list *get_scope_type(uint8_t type, void *filter1,
					 void *filter2)
{
	struct scope_list *list = NULL;
	struct scope_node *scope_node;
	struct hciseq_node *seq_node = seq->current;
	uint16_t opcode, node_opcode;
	uint8_t node_ogf, ogf = 0x00;
	uint16_t node_ocf, ocf = 0x0000;
	uint8_t node_evt, evt = 0x00;
	bool match;
	int pos = 1;
	struct hciseq_attr *attr;

	if (type == BT_H4_CMD_PKT) {
		ogf = *((uint8_t *) filter1);
		ocf = *((uint16_t *) filter2);
		opcode = cmd_opcode_pack(ogf, ocf);

		if (opcode > 0x2FFF) {
			attr = NULL;
		} else {
			attr = type_cfg->cmd[opcode];
			if (attr == NULL) {
				attr = malloc(sizeof(*attr));
				type_cfg->cmd[opcode] = attr;
			}
		}
	} else if (type == BT_H4_EVT_PKT) {
		evt = *((uint8_t *) filter1);
		attr = type_cfg->evt[evt];

		if (attr == NULL) {
			attr = malloc(sizeof(*attr));
			type_cfg->evt[evt] = attr;
		}
	} else if (type == BT_H4_ACL_PKT) {
		attr = type_cfg->acl;
		if (attr == NULL) {
			attr = malloc(sizeof(*attr));
			type_cfg->acl = attr;
		}
	} else {
		attr = NULL;
	}

	/* add matching packets in sequence */
	while (seq_node != NULL) {
		match = false;
		if (((uint8_t *) seq_node->frame->data)[0] == type) {
			if (type == BT_H4_CMD_PKT) {
				node_opcode = *((uint16_t *)
						(seq_node->frame->data + 1));
				node_ogf = cmd_opcode_ogf(node_opcode);
				node_ocf = cmd_opcode_ocf(node_opcode);
				if (node_ogf == ogf && node_ocf == ocf)
					match = true;
			} else if (type == BT_H4_EVT_PKT) {
				node_evt = ((uint8_t *)
						seq_node->frame->data)[1];
				if (evt == node_evt)
					match = true;
			} else if (type == BT_H4_ACL_PKT) {
				match = true;
			}
		}

		if (match) {
			if (verbose)
				printf("\tadd packet [%d]\n", pos);

			if (list == NULL) {
				list = malloc(sizeof(*list));
				scope_node = malloc(sizeof(*scope_node));
				list->head = scope_node;
			} else {
				scope_node->next = malloc(sizeof(*scope_node));
				scope_node = scope_node->next;
			}
			scope_node->attr = seq_node->attr;
			scope_node->pos = pos;
			scope_node->next = NULL;
		}
		seq_node = seq_node->next;
		pos++;
	}

	/* add type config */
	if (attr != NULL) {
		if (list == NULL) {
			list = malloc(sizeof(*list));
			scope_node = malloc(sizeof(*scope_node));
			list->head = scope_node;
		} else {
			scope_node->next = malloc(sizeof(*scope_node));
			scope_node = scope_node->next;
		}

		scope_node->attr = attr;
		scope_node->pos = 0;
		scope_node->next = NULL;
	}

	return list;
}
Example #10
0
int hci_send_req(struct hci_request *r, BOOL async)
{
  uint8_t *ptr;
  uint16_t opcode = htobs(cmd_opcode_pack(r->ogf, r->ocf));
  hci_event_pckt *event_pckt;
  hci_uart_pckt *hci_hdr;
  int to = /*1;*/ DEFAULT_TIMEOUT;
  struct timer t;
  tHciDataPacket * hciReadPacket = NULL;
  tListNode hciTempQueue;
  
  list_init_head((tListNode*)&hciTempQueue);

  // cannot be processed, due to reentrancy
  if (hciAwaitReply) {
    return -1;
  }

  hciAwaitReply = TRUE;
  
  hci_send_cmd(r->ogf, r->ocf, r->clen, r->cparam);
  
  if(async){
    goto done;
  }
  
  /* Minimum timeout is 1. */
  if(to == 0)
    to = 1;
  
  Timer_Set(&t, to);
  
  while(1) {
    evt_cmd_complete *cc;
    evt_cmd_status *cs;
    evt_le_meta_event *me;
    int len;

    // we're done with the sending, wait for a reply from the bluenrg
    io_seproxyhal_general_status();

    // perform io_event based loop to wait for BLUENRG_RECV_EVENT
    for (;;) {
      io_seproxyhal_spi_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
      // check if event is a ticker event
      unsigned int ticker_event = G_io_seproxyhal_spi_buffer[0] == SEPROXYHAL_TAG_TICKER_EVENT;

      // process IOs, and BLE fetch, ble queue is updated through common code
      io_seproxyhal_handle_event();

      // don't ack the BLUENRG_RECV_EVENT as we would require to reply another command to it.
      if(!list_is_empty((tListNode*)&hciReadPktRxQueue)){
        /* Extract packet from HCI event queue. */
        //Disable_SPI_IRQ();
        list_remove_head((tListNode*)&hciReadPktRxQueue, (tListNode **)&hciReadPacket);    
        list_insert_tail((tListNode*)&hciTempQueue, (tListNode *)hciReadPacket);
        
        hci_hdr = (void *)hciReadPacket->dataBuff;
        if(hci_hdr->type != HCI_EVENT_PKT){
          move_list((tListNode*)&hciReadPktPool, (tListNode*)&hciTempQueue);  
          //list_insert_tail((tListNode*)&hciTempQueue, (tListNode *)hciReadPacket); // See comment below
          //Enable_SPI_IRQ();
          goto case_USER_PROCESS;
        }
        
        event_pckt = (void *) (hci_hdr->data);
        
        ptr = hciReadPacket->dataBuff + (1 + HCI_EVENT_HDR_SIZE);
        len = hciReadPacket->data_len - (1 + HCI_EVENT_HDR_SIZE);
        
        /* In the meantime there could be other events from the controller.
        In this case, insert the packet in a different queue. These packets will be
        inserted back in the main queue just before exiting from send_req().
        */

        event_pckt = (void *) (hci_hdr->data);
        switch (event_pckt->evt) {
          
        case EVT_CMD_STATUS:
          cs = (void *) ptr;
          
          if (cs->opcode != opcode) {
            goto case_USER_PROCESS;
          }
          
          if (r->event != EVT_CMD_STATUS) {
            goto case_USER_PROCESS;
          }
          
          r->rlen = MIN(len, r->rlen);
          Osal_MemCpy(r->rparam, ptr, r->rlen);
          goto done;
          
        case EVT_CMD_COMPLETE:
          cc = (void *) ptr;
          
          if (cc->opcode != opcode) {
            goto case_USER_PROCESS;
          }
          
          ptr += EVT_CMD_COMPLETE_SIZE;
          len -= EVT_CMD_COMPLETE_SIZE;
          
          r->rlen = MIN(len, r->rlen);
          Osal_MemCpy(r->rparam, ptr, r->rlen);
          goto done;
          
        case EVT_LE_META_EVENT:
          me = (void *) ptr;
          
          if (me->subevent != r->event) {
            goto case_USER_PROCESS;
          }
          
          len -= 1;
          r->rlen = MIN(len, r->rlen);
          Osal_MemCpy(r->rparam, me->data, r->rlen);
          goto done;
          
        case EVT_HARDWARE_ERROR:
          return -1;

        default:      
        case_USER_PROCESS:
          HCI_Event_CB(hciReadPacket->dataBuff);
          break;
        }
      }

      // timeout
      if (ticker_event) {
        if (to) {
          to--;
        }
        // don't signal timeout if the event has been closed by handle event to avoid sending commands after a status has been issued
        else if (!io_seproxyhal_spi_is_status_sent()) {
          return -1;
        }
      }

      // ack the received event we have processed
      io_seproxyhal_general_status();
    }
    
    
    //Enable_SPI_IRQ();
    
  }
  
failed: 
  move_list((tListNode*)&hciReadPktPool, (tListNode*)&hciTempQueue);  
  hciAwaitReply = FALSE;
  //Enable_SPI_IRQ();
  return -1;
  
done:
  // Insert the packet back into the pool.
  /*
  if (hciReadPacket) {
    list_insert_head((tListNode*)&hciReadPktPool, (tListNode *)hciReadPacket); 
  }
  */
  move_list((tListNode*)&hciReadPktPool, (tListNode*)&hciTempQueue);
  hciAwaitReply = FALSE;
  //Enable_SPI_IRQ();
  return 0;
}
Example #11
0
/* 'to' is timeout in system clock ticks.  */
int hci_send_req(struct hci_request *r)
{
	uint8_t *ptr;
	uint16_t opcode = htobs(cmd_opcode_pack(r->ogf, r->ocf));
	hci_event_pckt *event_pckt;
	hci_uart_pckt *hci_hdr;
	int try;
    int to = DEFAULT_TIMEOUT;
    
	new_packet = FALSE;
	hci_set_packet_complete_callback(new_hci_event);
	if (hci_send_cmd(r->ogf, r->ocf, r->clen, r->cparam) < 0)
		goto failed;
    
	try = 10;
	while (try--) {
		evt_cmd_complete *cc;
		evt_cmd_status *cs;
		evt_le_meta_event *me;
		int len;
        
        /* Minimum timeout is 1. */
        if(to == 0)
            to = 1;
        
		if (to > 0) {
			struct timer t;
            
			Timer_Set(&t, to);
            
			while(1){
				if(Timer_Expired(&t)){
					goto failed;
				}
				if(new_packet){
					break;
				}
			}
		}
        
		hci_hdr = (void *)hci_buffer;
		if(hci_hdr->type != HCI_EVENT_PKT){
            new_packet = FALSE;
            Enable_SPI_IRQ();
            continue;
        }
        
		event_pckt = (void *) (hci_hdr->data);
        
		ptr = hci_buffer + (1 + HCI_EVENT_HDR_SIZE);
		len = hci_pckt_len - (1 + HCI_EVENT_HDR_SIZE);
        
		switch (event_pckt->evt) {
            
		case EVT_CMD_STATUS:
			cs = (void *) ptr;
            
			if (cs->opcode != opcode)
				break;
            
			if (r->event != EVT_CMD_STATUS) {
				if (cs->status) {
					goto failed;
				}
				break;
			}
            
			r->rlen = MIN(len, r->rlen);
			Osal_MemCpy(r->rparam, ptr, r->rlen);
			goto done;
            
		case EVT_CMD_COMPLETE:
			cc = (void *) ptr;
            
			if (cc->opcode != opcode)
				break;
            
			ptr += EVT_CMD_COMPLETE_SIZE;
			len -= EVT_CMD_COMPLETE_SIZE;
            
			r->rlen = MIN(len, r->rlen);
			Osal_MemCpy(r->rparam, ptr, r->rlen);
			goto done;
            
		case EVT_LE_META_EVENT:
			me = (void *) ptr;
            
			if (me->subevent != r->event)
				break;
            
			len -= 1;
			r->rlen = MIN(len, r->rlen);
			Osal_MemCpy(r->rparam, me->data, r->rlen);
			goto done;
            
        case EVT_HARDWARE_ERROR:            
            goto failed;
            
		default:
            break; // In the meantime there could be other events from the controller.
		}
        
		new_packet = FALSE;
		Enable_SPI_IRQ();
        
	}
    
failed:
	hci_set_packet_complete_callback(NULL);
	Enable_SPI_IRQ();
	return -1;
    
done:
	hci_set_packet_complete_callback(NULL);
	Enable_SPI_IRQ();
	return 0;
}

int hci_reset()
{
  	struct hci_request rq;
	uint8_t status;

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_HOST_CTL;
	rq.ocf = OCF_RESET;
	rq.rparam = &status;
	rq.rlen = 1;

	if (hci_send_req(&rq) < 0)
		return -1;

	if (status) {
		return -1;
	}

	return 0;  
}

int hci_disconnect(uint16_t	handle, uint8_t reason)
{
  struct hci_request rq;
	disconnect_cp cp;
	uint8_t status;
  
	cp.handle = handle;
	cp.reason = reason;

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LINK_CTL;
	rq.ocf = OCF_DISCONNECT;
    rq.cparam = &cp;
	rq.clen = DISCONNECT_CP_SIZE;
    rq.event = EVT_CMD_STATUS;
	rq.rparam = &status;
	rq.rlen = 1;

	if (hci_send_req(&rq) < 0)
		return -1;

	if (status) {
		return -1;
	}

	return 0;  
}

int hci_le_read_local_version(uint8_t *hci_version, uint16_t *hci_revision, uint8_t *lmp_pal_version, 
			      uint16_t *manufacturer_name, uint16_t *lmp_pal_subversion)
{
	struct hci_request rq;
	read_local_version_rp resp;

	Osal_MemSet(&resp, 0, sizeof(resp));

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_INFO_PARAM;
	rq.ocf = OCF_READ_LOCAL_VERSION;
	rq.cparam = NULL;
	rq.clen = 0;
	rq.rparam = &resp;
	rq.rlen = READ_LOCAL_VERSION_RP_SIZE;

	if (hci_send_req(&rq) < 0)
		return -1;

	if (resp.status) {
		return -1;
	}


	*hci_version = resp.hci_version;
	*hci_revision =  btohs(resp.hci_revision);
	*lmp_pal_version = resp.lmp_pal_version;
	*manufacturer_name = btohs(resp.manufacturer_name);
	*lmp_pal_subversion = btohs(resp.lmp_pal_subversion);

	return 0;
}

int hci_le_read_buffer_size(uint16_t *pkt_len, uint8_t *max_pkt)
{
	struct hci_request rq;
	le_read_buffer_size_rp resp;

	Osal_MemSet(&resp, 0, sizeof(resp));

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_READ_BUFFER_SIZE;
	rq.cparam = NULL;
	rq.clen = 0;
	rq.rparam = &resp;
	rq.rlen = LE_READ_BUFFER_SIZE_RP_SIZE;

	if (hci_send_req(&rq) < 0)
		return -1;

	if (resp.status) {
		return -1;
	}
	
	*pkt_len = resp.pkt_len;
	*max_pkt = resp.max_pkt;

	return 0;
}

int hci_le_set_advertising_parameters(uint16_t min_interval, uint16_t max_interval, uint8_t advtype,
		uint8_t own_bdaddr_type, uint8_t direct_bdaddr_type, tBDAddr direct_bdaddr, uint8_t chan_map,
		uint8_t filter)
{
	struct hci_request rq;
	le_set_adv_parameters_cp adv_cp;
	uint8_t status;

	Osal_MemSet(&adv_cp, 0, sizeof(adv_cp));
	adv_cp.min_interval = min_interval;
	adv_cp.max_interval = max_interval;
	adv_cp.advtype = advtype;
	adv_cp.own_bdaddr_type = own_bdaddr_type;
	adv_cp.direct_bdaddr_type = direct_bdaddr_type;
    Osal_MemCpy(adv_cp.direct_bdaddr,direct_bdaddr,sizeof(adv_cp.direct_bdaddr));
	adv_cp.chan_map = chan_map;
	adv_cp.filter = filter;

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_SET_ADV_PARAMETERS;
	rq.cparam = &adv_cp;
	rq.clen = LE_SET_ADV_PARAMETERS_CP_SIZE;
	rq.rparam = &status;
	rq.rlen = 1;

	if (hci_send_req(&rq) < 0)
		return -1;

	if (status) {
		return -1;
	}

	return 0;
}

int hci_le_set_advertising_data(uint8_t length, const uint8_t data[])
{
	struct hci_request rq;
	le_set_adv_data_cp adv_cp;
	uint8_t status;

	Osal_MemSet(&adv_cp, 0, sizeof(adv_cp));
	adv_cp.length = length;
	Osal_MemCpy(adv_cp.data, data, MIN(31,length));

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_SET_ADV_DATA;
	rq.cparam = &adv_cp;
	rq.clen = LE_SET_ADV_DATA_CP_SIZE;
	rq.rparam = &status;
	rq.rlen = 1;

	if (hci_send_req(&rq) < 0)
		return -1;

	if (status) {
		return -1;
	}

	return 0;
}

int hci_le_set_advertise_enable(uint8_t enable)
{
	struct hci_request rq;
	le_set_advertise_enable_cp adv_cp;
	uint8_t status;

	Osal_MemSet(&adv_cp, 0, sizeof(adv_cp));
	adv_cp.enable = enable?1:0;

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_SET_ADVERTISE_ENABLE;
	rq.cparam = &adv_cp;
	rq.clen = LE_SET_ADVERTISE_ENABLE_CP_SIZE;
	rq.rparam = &status;
	rq.rlen = 1;

	if (hci_send_req(&rq) < 0)
		return -1;

	if (status) {
		return -1;
	}

	return 0;
}

int hci_le_rand(uint8_t random_number[8])
{
	struct hci_request rq;
	le_rand_rp resp;

	Osal_MemSet(&resp, 0, sizeof(resp));

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_RAND;
	rq.cparam = NULL;
	rq.clen = 0;
	rq.rparam = &resp;
	rq.rlen = LE_RAND_RP_SIZE;

	if (hci_send_req(&rq) < 0)
		return -1;

	if (resp.status) {
		return -1;
	}
    
    Osal_MemCpy(random_number, resp.random, 8);

	return 0;
}

int hci_le_set_scan_resp_data(uint8_t length, const uint8_t data[])
{
	struct hci_request rq;
	le_set_scan_response_data_cp scan_resp_cp;
	uint8_t status;

	Osal_MemSet(&scan_resp_cp, 0, sizeof(scan_resp_cp));
	scan_resp_cp.length = length;
	Osal_MemCpy(scan_resp_cp.data, data, MIN(31,length));

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_SET_SCAN_RESPONSE_DATA;
	rq.cparam = &scan_resp_cp;
	rq.clen = LE_SET_SCAN_RESPONSE_DATA_CP_SIZE;
	rq.rparam = &status;
	rq.rlen = 1;

	if (hci_send_req(&rq) < 0)
		return -1;

	if (status) {
		return -1;
	}

	return 0;
}

int hci_le_read_advertising_channel_tx_power(int8_t *tx_power_level)
{
	struct hci_request rq;
	le_read_adv_channel_tx_power_rp resp;

	Osal_MemSet(&resp, 0, sizeof(resp));

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_READ_ADV_CHANNEL_TX_POWER;
	rq.cparam = NULL;
	rq.clen = 0;
	rq.rparam = &resp;
	rq.rlen = LE_RAND_RP_SIZE;

	if (hci_send_req(&rq) < 0)
		return -1;

	if (resp.status) {
		return -1;
	}

	*tx_power_level = resp.level;

	return 0;
}

int hci_le_set_random_address(tBDAddr bdaddr)
{
	struct hci_request rq;
	le_set_random_address_cp set_rand_addr_cp;
	uint8_t status;

	Osal_MemSet(&set_rand_addr_cp, 0, sizeof(set_rand_addr_cp));
	Osal_MemCpy(set_rand_addr_cp.bdaddr, bdaddr, sizeof(tBDAddr));

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_SET_RANDOM_ADDRESS;
	rq.cparam = &set_rand_addr_cp;
	rq.clen = LE_SET_RANDOM_ADDRESS_CP_SIZE;
	rq.rparam = &status;
	rq.rlen = 1;

	if (hci_send_req(&rq) < 0)
		return -1;

	if (status) {
		return -1;
	}

	return 0;
}

int hci_read_bd_addr(tBDAddr bdaddr)
{
	struct hci_request rq;
	read_bd_addr_rp resp;

	Osal_MemSet(&resp, 0, sizeof(resp));

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_INFO_PARAM;
	rq.ocf = OCF_READ_BD_ADDR;
	rq.cparam = NULL;
	rq.clen = 0;
	rq.rparam = &resp;
	rq.rlen = READ_BD_ADDR_RP_SIZE;

	if (hci_send_req(&rq) < 0)
		return -1;

	if (resp.status) {
		return -1;
	}
	Osal_MemCpy(bdaddr, resp.bdaddr, sizeof(tBDAddr));

	return 0;
}

int hci_le_create_connection(uint16_t interval,	uint16_t window, uint8_t initiator_filter, uint8_t peer_bdaddr_type,
                             const tBDAddr peer_bdaddr,	uint8_t	own_bdaddr_type, uint16_t min_interval,	uint16_t max_interval,
                             uint16_t latency,	uint16_t supervision_timeout, uint16_t min_ce_length, uint16_t max_ce_length)
{
	struct hci_request rq;
	le_create_connection_cp create_cp;
	uint8_t status;

	Osal_MemSet(&create_cp, 0, sizeof(create_cp));
	create_cp.interval = interval;
	create_cp.window =  window;
	create_cp.initiator_filter = initiator_filter;
	create_cp.peer_bdaddr_type = peer_bdaddr_type;
	Osal_MemCpy(create_cp.peer_bdaddr, peer_bdaddr, sizeof(tBDAddr));
	create_cp.own_bdaddr_type = own_bdaddr_type;
	create_cp.min_interval=min_interval;
	create_cp.max_interval=max_interval;
	create_cp.latency = latency;
	create_cp.supervision_timeout=supervision_timeout;
	create_cp.min_ce_length=min_ce_length;
	create_cp.max_ce_length=max_ce_length;

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_CREATE_CONN;
	rq.cparam = &create_cp;
	rq.clen = LE_CREATE_CONN_CP_SIZE;
    rq.event = EVT_CMD_STATUS;
	rq.rparam = &status;
	rq.rlen = 1;

	if (hci_send_req(&rq) < 0)
		return -1;

	if (status) {
		return -1;
	}

	return 0;
}

int hci_le_encrypt(uint8_t key[16], uint8_t plaintextData[16], uint8_t encryptedData[16])
{
	struct hci_request rq;
	le_encrypt_cp params;
	le_encrypt_rp resp;
	
	Osal_MemSet(&resp, 0, sizeof(resp));

	Osal_MemCpy(params.key, key, 16);
	Osal_MemCpy(params.plaintext, plaintextData, 16);

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_ENCRYPT;
	rq.cparam = &params;
	rq.clen = LE_ENCRYPT_CP_SIZE;
	rq.rparam = &resp;
	rq.rlen = LE_ENCRYPT_RP_SIZE;

	if (hci_send_req(&rq) < 0){
		return -1;
	}

	if (resp.status) {
		return -1;
	}
	
	Osal_MemCpy(encryptedData, resp.encdata, 16);

	return 0;
}

int hci_le_ltk_request_reply(uint8_t key[16])
{
	struct hci_request rq;
	le_ltk_reply_cp params;
	le_ltk_reply_rp resp;
	
	Osal_MemSet(&resp, 0, sizeof(resp));

	params.handle = 1;
	Osal_MemCpy(params.key, key, 16);

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_LTK_REPLY;
	rq.cparam = &params;
	rq.clen = LE_LTK_REPLY_CP_SIZE;
	rq.rparam = &resp;
	rq.rlen = LE_LTK_REPLY_RP_SIZE;

	if (hci_send_req(&rq) < 0)
		return -1;

	if (resp.status) {
		return -1;
	}

	return 0;
}

int hci_le_ltk_request_neg_reply()
{
	struct hci_request rq;
	le_ltk_neg_reply_cp params;
	le_ltk_neg_reply_rp resp;
	
	Osal_MemSet(&resp, 0, sizeof(resp));

	params.handle = 1;

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_LTK_NEG_REPLY;
	rq.cparam = &params;
	rq.clen = LE_LTK_NEG_REPLY_CP_SIZE;
	rq.rparam = &resp;
	rq.rlen = LE_LTK_NEG_REPLY_RP_SIZE;

	if (hci_send_req(&rq) < 0)
		return -1;

	if (resp.status) {
		return -1;
	}

	return 0;
}

int hci_le_read_white_list_size(uint8_t *size)
{
	struct hci_request rq;
    le_read_white_list_size_rp resp;
	
	Osal_MemSet(&resp, 0, sizeof(resp));

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_READ_WHITE_LIST_SIZE;
	rq.rparam = &resp;
	rq.rlen = LE_READ_WHITE_LIST_SIZE_RP_SIZE;

	if (hci_send_req(&rq) < 0){
		return -1;
	}

	if (resp.status) {
		return -1;
	}
    
    *size = resp.size;

	return 0;
}

int hci_le_clear_white_list()
{
	struct hci_request rq;
	uint8_t status;

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_CLEAR_WHITE_LIST;
	rq.rparam = &status;
	rq.rlen = 1;

	if (hci_send_req(&rq) < 0){
		return -1;
	}

	if (status) {
		return -1;
	}

	return 0;
}

int hci_le_add_device_to_white_list(uint8_t	bdaddr_type, tBDAddr bdaddr)
{
	struct hci_request rq;
	le_add_device_to_white_list_cp params;
	uint8_t status;

	params.bdaddr_type = bdaddr_type;
	Osal_MemCpy(params.bdaddr, bdaddr, 6);

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_ADD_DEVICE_TO_WHITE_LIST;
	rq.cparam = &params;
	rq.clen = LE_ADD_DEVICE_TO_WHITE_LIST_CP_SIZE;
	rq.rparam = &status;
	rq.rlen = 1;

	if (hci_send_req(&rq) < 0){
		return -1;
	}

	if (status) {
		return -1;
	}

	return 0;
}

int hci_le_remove_device_from_white_list(uint8_t bdaddr_type, tBDAddr bdaddr)
{
	struct hci_request rq;
	le_remove_device_from_white_list_cp params;
	uint8_t status;

	params.bdaddr_type = bdaddr_type;
	Osal_MemCpy(params.bdaddr, bdaddr, 6);

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_REMOVE_DEVICE_FROM_WHITE_LIST;
	rq.cparam = &params;
	rq.clen = LE_REMOVE_DEVICE_FROM_WHITE_LIST_CP_SIZE;
	rq.rparam = &status;
	rq.rlen = 1;

	if (hci_send_req(&rq) < 0){
		return -1;
	}

	if (status) {
		return -1;
	}

	return 0;
}

int hci_read_transmit_power_level(uint16_t *conn_handle, uint8_t type, int8_t * tx_level)
{
    struct hci_request rq;
	read_transmit_power_level_cp params;
	read_transmit_power_level_rp resp;
	
	Osal_MemSet(&resp, 0, sizeof(resp));

	params.handle = *conn_handle;
	params.type = type;

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_HOST_CTL;
	rq.ocf = OCF_READ_TRANSMIT_POWER_LEVEL;
	rq.cparam = &params;
	rq.clen = READ_TRANSMIT_POWER_LEVEL_CP_SIZE;
	rq.rparam = &resp;
	rq.rlen = READ_TRANSMIT_POWER_LEVEL_RP_SIZE;

	if (hci_send_req(&rq) < 0){
		return -1;
	}

	if (resp.status) {
		return -1;
	}
	
    *conn_handle = resp.handle;
    *tx_level = resp.handle;

	return 0;
}

int hci_read_rssi(uint16_t *conn_handle, int8_t * rssi)
{
    struct hci_request rq;
	read_rssi_cp params;
	read_rssi_rp resp;
	
	Osal_MemSet(&resp, 0, sizeof(resp));

	params.handle = *conn_handle;

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_STATUS_PARAM;
	rq.ocf = OCF_READ_RSSI;
	rq.cparam = &params;
	rq.clen = READ_RSSI_CP_SIZE;
	rq.rparam = &resp;
	rq.rlen = READ_RSSI_RP_SIZE;

	if (hci_send_req(&rq) < 0){
		return -1;
	}

	if (resp.status) {
		return -1;
	}
	
    *conn_handle = resp.handle;
    *rssi = resp.rssi;

	return 0;
}

int hci_le_read_local_supported_features(uint8_t *features)
{
	struct hci_request rq;
    le_read_local_supported_features_rp resp;
	
	Osal_MemSet(&resp, 0, sizeof(resp));

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_READ_LOCAL_SUPPORTED_FEATURES;
	rq.rparam = &resp;
	rq.rlen = LE_READ_LOCAL_SUPPORTED_FEATURES_RP_SIZE;

	if (hci_send_req(&rq) < 0){
		return -1;
	}

	if (resp.status) {
		return -1;
	}
    
    Osal_MemCpy(features, resp.features, sizeof(resp.features));

	return 0;
}

int hci_le_read_channel_map(uint16_t conn_handle, uint8_t ch_map[5])
{
    struct hci_request rq;
	le_read_channel_map_cp params;
	le_read_channel_map_rp resp;
	
	Osal_MemSet(&resp, 0, sizeof(resp));

	params.handle = conn_handle;

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_READ_CHANNEL_MAP;
	rq.cparam = &params;
	rq.clen = LE_READ_CHANNEL_MAP_CP_SIZE;
	rq.rparam = &resp;
	rq.rlen = LE_READ_CHANNEL_MAP_RP_SIZE;

	if (hci_send_req(&rq) < 0){
		return -1;
	}

	if (resp.status) {
		return -1;
	}
    
    Osal_MemCpy(ch_map, resp.map, 5);

	return 0;
}

int hci_le_read_supported_states(uint8_t states[8])
{
	struct hci_request rq;
    le_read_supported_states_rp resp;
	
	Osal_MemSet(&resp, 0, sizeof(resp));

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_READ_SUPPORTED_STATES;
	rq.rparam = &resp;
	rq.rlen = LE_READ_SUPPORTED_STATES_RP_SIZE;

	if (hci_send_req(&rq) < 0){
		return -1;
	}

	if (resp.status) {
		return -1;
	}
    
    Osal_MemCpy(states, resp.states, 8);

	return 0;
}

int hci_le_receiver_test(uint8_t frequency)
{
	struct hci_request rq;
	le_receiver_test_cp params;
	uint8_t status;

	params.frequency = frequency;

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_RECEIVER_TEST;
	rq.cparam = &params;
	rq.clen = LE_RECEIVER_TEST_CP_SIZE;
	rq.rparam = &status;
	rq.rlen = 1;

	if (hci_send_req(&rq) < 0){
		return -1;
	}

	if (status) {
		return -1;
	}

	return 0;
}

int hci_le_transmitter_test(uint8_t frequency, uint8_t length, uint8_t payload)
{
	struct hci_request rq;
	le_transmitter_test_cp params;
	uint8_t status;

	params.frequency = frequency;
    params.length = length;
    params.payload = payload;

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_TRANSMITTER_TEST;
	rq.cparam = &params;
	rq.clen = LE_TRANSMITTER_TEST_CP_SIZE;
	rq.rparam = &status;
	rq.rlen = 1;

	if (hci_send_req(&rq) < 0){
		return -1;
	}

	if (status) {
		return -1;
	}

	return 0;
}

int hci_le_test_end(uint16_t *num_pkts)
{
	struct hci_request rq;
    le_test_end_rp resp;
	
	Osal_MemSet(&resp, 0, sizeof(resp));

	Osal_MemSet(&rq, 0, sizeof(rq));
	rq.ogf = OGF_LE_CTL;
	rq.ocf = OCF_LE_TEST_END;
	rq.rparam = &resp;
	rq.rlen = LE_TEST_END_RP_SIZE;

	if (hci_send_req(&rq) < 0){
		return -1;
	}

	if (resp.status) {
		return -1;
	}
    
    *num_pkts = resp.num_pkts;

	return 0;
}