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); }; }
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; } }
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); }
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); }
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; }
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; }
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; }
/* '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 = ¶ms; 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 = ¶ms; 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 = ¶ms; 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 = ¶ms; 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 = ¶ms; 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 = ¶ms; 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 = ¶ms; 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 = ¶ms; 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 = ¶ms; 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 = ¶ms; 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; }