Repository: incubator-mynewt-larva Updated Branches: refs/heads/master 4fd25c482 -> b612bf4bb
Fix some issues with initiating and starting a connection. Add API to send data packets from host to controller Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/commit/b612bf4b Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/tree/b612bf4b Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/diff/b612bf4b Branch: refs/heads/master Commit: b612bf4bbf730671fbebaec30c996942a67d82ce Parents: 30e9b33 Author: wes3 <w...@micosa.io> Authored: Tue Dec 1 12:47:41 2015 -0800 Committer: wes3 <w...@micosa.io> Committed: Tue Dec 1 12:47:48 2015 -0800 ---------------------------------------------------------------------- .../controller/include/controller/ble_ll.h | 18 +- .../controller/include/controller/ble_ll_conn.h | 3 +- .../controller/include/controller/ble_ll_hci.h | 2 + net/nimble/controller/src/ble_ll.c | 72 ++++- net/nimble/controller/src/ble_ll_adv.c | 7 +- net/nimble/controller/src/ble_ll_conn.c | 285 ++++++++++++------- net/nimble/controller/src/ble_ll_hci.c | 8 + net/nimble/host/src/ble_hs.c | 2 +- net/nimble/host/src/host_dbg.c | 45 ++- net/nimble/host/src/host_hci_cmd.c | 2 +- net/nimble/include/nimble/ble.h | 14 +- net/nimble/include/nimble/hci_transport.h | 3 + project/bletest/bletest.yml | 1 + project/bletest/src/main.c | 54 +++- 14 files changed, 390 insertions(+), 126 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b612bf4b/net/nimble/controller/include/controller/ble_ll.h ---------------------------------------------------------------------- diff --git a/net/nimble/controller/include/controller/ble_ll.h b/net/nimble/controller/include/controller/ble_ll.h index a39f4a1..aff9aab 100644 --- a/net/nimble/controller/include/controller/ble_ll.h +++ b/net/nimble/controller/include/controller/ble_ll.h @@ -35,15 +35,17 @@ struct ble_ll_obj /* Task event queue */ struct os_eventq ll_evq; - /* Receive packet (from phy) event */ - struct os_event ll_rx_pkt_ev; - /* Wait for response timer */ struct cpu_timer ll_wfr_timer; ble_ll_wfr_func ll_wfr_func; - /* Packet receive queue */ + /* Packet receive queue (and event). Holds received packets from PHY */ + struct os_event ll_rx_pkt_ev; STAILQ_HEAD(ll_rxpkt_qh, os_mbuf_pkthdr) ll_rx_pkt_q; + + /* Packet transmit queue */ + struct os_event ll_tx_pkt_ev; + STAILQ_HEAD(ll_txpkt_qh, os_mbuf_pkthdr) ll_tx_pkt_q; }; extern struct ble_ll_obj g_ble_ll_data; @@ -83,6 +85,7 @@ extern struct ble_ll_stats g_ble_ll_stats; #define BLE_LL_EVENT_SCAN_WIN_END (OS_EVENT_T_PERUSER + 3) #define BLE_LL_EVENT_CONN_SPVN_TMO (OS_EVENT_T_PERUSER + 4) #define BLE_LL_EVENT_CONN_EV_END (OS_EVENT_T_PERUSER + 5) +#define BLE_LL_EVENT_TX_PKT_IN (OS_EVENT_T_PERUSER + 6) /* LL Features */ #define BLE_LL_FEAT_LE_ENCRYPTION (0x01) @@ -408,6 +411,13 @@ int ble_ll_is_resolvable_priv_addr(uint8_t *addr); /* Is 'addr' our device address? 'addr_type' is public (0) or random (!=0) */ int ble_ll_is_our_devaddr(uint8_t *addr, int addr_type); +/** + * Called to put a packet on the Link Layer transmit packet queue. + * + * @param txpdu Pointer to transmit packet + */ +void ble_ll_acl_data_in(struct os_mbuf *txpkt); + /*--- PHY interfaces ---*/ /* Called by the PHY when a packet has started */ int ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan); http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b612bf4b/net/nimble/controller/include/controller/ble_ll_conn.h ---------------------------------------------------------------------- diff --git a/net/nimble/controller/include/controller/ble_ll_conn.h b/net/nimble/controller/include/controller/ble_ll_conn.h index f58a140..e5a359c 100644 --- a/net/nimble/controller/include/controller/ble_ll_conn.h +++ b/net/nimble/controller/include/controller/ble_ll_conn.h @@ -33,12 +33,13 @@ int ble_ll_conn_is_peer_adv(uint8_t addr_type, uint8_t *adva); int ble_ll_conn_request_send(uint8_t addr_type, uint8_t *adva); void ble_ll_init_rx_pdu_proc(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr); int ble_ll_init_rx_pdu_end(struct os_mbuf *rxpdu); -void ble_ll_conn_slave_start(uint8_t *rxbuf); +int ble_ll_conn_slave_start(uint8_t *rxbuf); void ble_ll_conn_spvn_timeout(void *arg); void ble_ll_conn_event_end(void *arg); void ble_ll_conn_init(void); void ble_ll_conn_rx_pdu_start(void); int ble_ll_conn_rx_pdu_end(struct os_mbuf *rxpdu, uint8_t crcok); void ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, uint8_t crcok); +void ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t len); #endif /* H_BLE_LL_CONN_ */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b612bf4b/net/nimble/controller/include/controller/ble_ll_hci.h ---------------------------------------------------------------------- diff --git a/net/nimble/controller/include/controller/ble_ll_hci.h b/net/nimble/controller/include/controller/ble_ll_hci.h index acc9701..222b772 100644 --- a/net/nimble/controller/include/controller/ble_ll_hci.h +++ b/net/nimble/controller/include/controller/ble_ll_hci.h @@ -17,6 +17,8 @@ #ifndef H_BLE_LL_HCI_ #define H_BLE_LL_HCI_ +/* XXX: I think the data packet length should be 251 for now. Not sure + how to set num data packets. */ /* Define the number of data packets that the controller can store */ #define BLE_LL_CFG_NUM_ACL_DATA_PKTS (4) #define BLE_LL_CFG_ACL_DATA_PKT_LEN (256) http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b612bf4b/net/nimble/controller/src/ble_ll.c ---------------------------------------------------------------------- diff --git a/net/nimble/controller/src/ble_ll.c b/net/nimble/controller/src/ble_ll.c index 679d859..2d6d466 100644 --- a/net/nimble/controller/src/ble_ll.c +++ b/net/nimble/controller/src/ble_ll.c @@ -63,7 +63,7 @@ struct ble_ll_stats g_ble_ll_stats; /* The BLE LL task data structure */ #define BLE_LL_TASK_PRI (OS_TASK_PRI_HIGHEST) -#define BLE_LL_STACK_SIZE (128) +#define BLE_LL_STACK_SIZE (256) struct os_task g_ble_ll_task; os_stack_t g_ble_ll_stack[BLE_LL_STACK_SIZE]; @@ -273,6 +273,48 @@ ble_ll_wfr_disable(void) } /** + * ll tx pkt in proc + * + * Process ACL data packet input from host + * + * Context: Link layer task + * + */ +void +ble_ll_tx_pkt_in_proc(void) +{ + uint16_t handle; + uint16_t length; + struct os_mbuf_pkthdr *pkthdr; + struct os_mbuf *om; + + /* Drain all packets off the queue */ + while (STAILQ_FIRST(&g_ble_ll_data.ll_tx_pkt_q)) { + /* Get mbuf pointer from packet header pointer */ + pkthdr = STAILQ_FIRST(&g_ble_ll_data.ll_tx_pkt_q); + om = (struct os_mbuf *)((uint8_t *)pkthdr - sizeof(struct os_mbuf)); + + /* Remove from queue */ + STAILQ_REMOVE_HEAD(&g_ble_ll_data.ll_tx_pkt_q, omp_next); + + /* XXX: regarding protecting the queue insert. Do I need to do that? + * I think I do since it will be a lower priority task. I am + talking about ll_tx_pkt_q here */ + + /* XXX: do I set ble header flags to zero here? */ + + /* XXX: what error checks do I want to perform here? Check valid + length packet header length, etc? */ + + /* Get handle and length */ + handle = le16toh(om->om_data); + length = le16toh(om->om_data + 2); + os_mbuf_adj(om, 2); + ble_ll_conn_tx_pkt_in(om, handle, length); + } +} + +/** * ll rx pkt in proc * * Process received packet from PHY. @@ -369,6 +411,21 @@ ble_ll_rx_pdu_in(struct os_mbuf *rxpdu) os_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_data.ll_rx_pkt_ev); } +/** + * Called to put a packet on the Link Layer transmit packet queue. + * + * @param txpdu Pointer to transmit packet + */ +void +ble_ll_acl_data_in(struct os_mbuf *txpkt) +{ + struct os_mbuf_pkthdr *pkthdr; + + pkthdr = OS_MBUF_PKTHDR(txpkt); + STAILQ_INSERT_TAIL(&g_ble_ll_data.ll_tx_pkt_q, pkthdr, omp_next); + os_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_data.ll_tx_pkt_ev); +} + /** * Called upon start of received PDU * @@ -608,6 +665,9 @@ ble_ll_task(void *arg) case BLE_LL_EVENT_RX_PKT_IN: ble_ll_rx_pkt_in_proc(); break; + case BLE_LL_EVENT_TX_PKT_IN: + ble_ll_tx_pkt_in_proc(); + break; case BLE_LL_EVENT_CONN_SPVN_TMO: ble_ll_conn_spvn_timeout(ev->ev_arg); break; @@ -665,14 +725,16 @@ ble_ll_init(void) /* Get pointer to global data object */ lldata = &g_ble_ll_data; - /* Initialize the receive queue */ - STAILQ_INIT(&lldata->ll_rx_pkt_q); - /* Initialize eventq */ os_eventq_init(&lldata->ll_evq); - /* Initialize receive packet (from phy) event */ + /* Initialize the transmit (from host) and receive (from phy) queues */ + STAILQ_INIT(&lldata->ll_tx_pkt_q); + STAILQ_INIT(&lldata->ll_rx_pkt_q); + + /* Initialize transmit (from host) and receive packet (from phy) event */ lldata->ll_rx_pkt_ev.ev_type = BLE_LL_EVENT_RX_PKT_IN; + lldata->ll_tx_pkt_ev.ev_type = BLE_LL_EVENT_TX_PKT_IN; /* Initialize wait for response timer */ cputime_timer_init(&g_ble_ll_data.ll_wfr_timer, ble_ll_wfr_timer_exp, http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b612bf4b/net/nimble/controller/src/ble_ll_adv.c ---------------------------------------------------------------------- diff --git a/net/nimble/controller/src/ble_ll_adv.c b/net/nimble/controller/src/ble_ll_adv.c index 334a918..19b49f0 100644 --- a/net/nimble/controller/src/ble_ll_adv.c +++ b/net/nimble/controller/src/ble_ll_adv.c @@ -885,9 +885,10 @@ ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, uint8_t flags) } if (valid) { - /* Stop advertising and start connection */ - ble_ll_adv_sm_stop(advsm); - ble_ll_conn_slave_start(rxbuf); + /* Try to start slave connection. If successful, stop advertising */ + if (ble_ll_conn_slave_start(rxbuf)) { + ble_ll_adv_sm_stop(advsm); + } } } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b612bf4b/net/nimble/controller/src/ble_ll_conn.c ---------------------------------------------------------------------- diff --git a/net/nimble/controller/src/ble_ll_conn.c b/net/nimble/controller/src/ble_ll_conn.c index 053a743..aee1b37 100644 --- a/net/nimble/controller/src/ble_ll_conn.c +++ b/net/nimble/controller/src/ble_ll_conn.c @@ -32,29 +32,22 @@ /* XXX TODO * 1) Add set channel map command and implement channel change procedure. - * 5) Implement getting a data packet. How do we do that? * 6) Make sure we have implemented all ways a connection can die/end. Not * a connection event; I mean the termination of a connection. * 8) Link layer control procedures and timers - * 9) Did we implement what happens if we receive a connection request from - * a device we are already connected to? We also need to check to see if we - * were asked to create a connection when one already exists. Note that + * 9) We also need to check to see if we were asked to create a connection + * when one already exists (the connection create command) Note that * an initiator should only send connection requests to devices it is not * already connected to. Make sure this cant happen. * 10) Make sure we check incoming data packets for size and all that. You * know, supported octets and all that. For both rx and tx. * 11) What kind of protection do I need on the conn_txq? The LL will need to * disable interrupts... not sure about ISR's. - * 12) Add/remove connection from the active connection list. * 13) Make sure we are setting the schedule end time properly for both slave * and master. We should just set this to the end of the connection event. * We might want to guarantee a IFS time as well since the next event needs * to be scheduled prior to the start of the event to account for the time it * takes to get a frame ready (which is pretty much the IFS time). - * 14) Make sure we set LLID correctly! - * 16) Make sure we are doing the right thing in the connection rx pdu start - * and end functions if we are a slave. - * 17) Make sure BLE header flags (TXD bit) is cleared when put on txq of conn */ /* XXX: this does not belong here! Move to transport? */ @@ -68,6 +61,7 @@ extern int ble_hs_rx_data(struct os_mbuf *om); * 2) See what connection state machine elements are purely master and * purely slave. We can make a union of them. * 3) Do I need a memory pool of connection elements? Probably not. + * 4) Modify mbuf code so that we dont free the mbuf if the pool is NULL. */ /* Connection event timing */ @@ -222,10 +216,10 @@ struct ble_ll_conn_sm /* Packet transmit queue */ STAILQ_HEAD(conn_txq_head, os_mbuf_pkthdr) conn_txq; - /* List entry for active connection pool */ + /* List entry for active/free connection pools */ union { - SLIST_ENTRY(ble_ll_conn_sm) conn_sle; - STAILQ_ENTRY(ble_ll_conn_sm) conn_stqe; + SLIST_ENTRY(ble_ll_conn_sm) act_sle; + STAILQ_ENTRY(ble_ll_conn_sm) free_stqe; }; /* empty pdu for connection */ @@ -255,6 +249,7 @@ struct ble_ll_conn_stats uint32_t cant_set_sched; uint32_t conn_ev_late; uint32_t wfr_expirations; + uint32_t handle_not_found; uint32_t no_tx_pdu; uint32_t no_conn_sm; uint32_t no_free_conn_sm; @@ -278,7 +273,7 @@ ble_ll_conn_sm_get(void) connsm = STAILQ_FIRST(&g_ble_ll_conn_free_list); if (connsm) { - STAILQ_REMOVE_HEAD(&g_ble_ll_conn_free_list, conn_stqe); + STAILQ_REMOVE_HEAD(&g_ble_ll_conn_free_list, free_stqe); } else { ++g_ble_ll_conn_stats.no_free_conn_sm; } @@ -387,11 +382,10 @@ ble_ll_conn_calc_access_addr(void) /* Cannot be access address or be 1 bit different */ aa = aa_high; - aa = (aa_high << 16) | aa_low; + aa = (aa << 16) | aa_low; bits_diff = 0; - mask = 0x00000001; temp = aa ^ BLE_ACCESS_ADDR_ADV; - for (mask = 0; mask <= 0x80000000; mask <<= 1) { + for (mask = 0x00000001; mask != 0; mask <<= 1) { if (mask & temp) { ++bits_diff; if (bits_diff > 1) { @@ -436,6 +430,9 @@ ble_ll_conn_calc_access_addr(void) if ((consecutive > 6) || (transitions > 24)) { continue; } + + /* We have a valid access address */ + break; } return aa; } @@ -540,7 +537,9 @@ ble_ll_conn_wait_txend(void *arg) /** * Called when we want to send a data channel pdu inside a connection event. - * + * + * Context: interrupt + * * @param connsm * * @return int 0: success; otherwise failure to transmit @@ -838,6 +837,68 @@ ble_ll_conn_spvn_timer_cb(void *arg) } /** + * Called when a create connection command has been received. This initializes + * a connection state machine in the master role. + * + * NOTE: Must be called before the state machine is started + * + * @param connsm + * @param hcc + */ +static void +ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm, + struct hci_create_conn *hcc) +{ + /* Must be master */ + connsm->conn_role = BLE_LL_CONN_ROLE_MASTER; + connsm->tx_win_size = BLE_LL_CONN_CFG_TX_WIN_SIZE; + connsm->tx_win_off = BLE_LL_CONN_CFG_TX_WIN_OFF; + connsm->master_sca = BLE_LL_CONN_CFG_MASTER_SCA; + + /* Hop increment is a random value between 5 and 16. */ + connsm->hop_inc = (rand() % 12) + 5; + + /* Set slave latency and supervision timeout */ + connsm->slave_latency = hcc->conn_latency; + connsm->supervision_tmo = hcc->supervision_timeout; + + /* Set own address type and peer address if needed */ + connsm->own_addr_type = hcc->own_addr_type; + if (hcc->filter_policy == 0) { + memcpy(&connsm->peer_addr, &hcc->peer_addr, BLE_DEV_ADDR_LEN); + connsm->peer_addr_type = hcc->peer_addr_type; + } + + /* XXX: for now, just make connection interval equal to max */ + connsm->conn_itvl = hcc->conn_itvl_max; + + /* Check the min/max CE lengths are less than connection interval */ + if (hcc->min_ce_len > (connsm->conn_itvl * 2)) { + connsm->min_ce_len = connsm->conn_itvl * 2; + } else { + connsm->min_ce_len = hcc->min_ce_len; + } + + if (hcc->max_ce_len > (connsm->conn_itvl * 2)) { + connsm->max_ce_len = connsm->conn_itvl * 2; + } else { + connsm->max_ce_len = hcc->max_ce_len; + } + + /* + * XXX: for now, just set the channel map to all 1's. Needs to get + * set to default or initialized or something + */ + connsm->num_used_chans = BLE_PHY_NUM_DATA_CHANS; + memset(connsm->chanmap, 0xff, BLE_LL_CONN_CHMAP_LEN - 1); + connsm->chanmap[4] = 0x1f; + + /* Calculate random access address and crc initialization value */ + connsm->access_addr = ble_ll_conn_calc_access_addr(); + connsm->crcinit = rand() & 0xffffff; +} + +/** * Start the connection state machine. This is done once per connection * when the HCI command "create connection" is issued to the controller or * when a slave receives a connect request, @@ -845,68 +906,16 @@ ble_ll_conn_spvn_timer_cb(void *arg) * @param connsm */ static void -ble_ll_conn_sm_start(struct ble_ll_conn_sm *connsm, struct hci_create_conn *hcc) +ble_ll_conn_sm_start(struct ble_ll_conn_sm *connsm) { struct ble_ll_conn_global_params *conn_params; - /* Reset event counter and last unmapped channel; get a handle */ + /* Reset event counter and last unmapped channel */ connsm->last_unmapped_chan = 0; connsm->event_cntr = 0; connsm->conn_state = BLE_LL_CONN_STATE_IDLE; connsm->allow_slave_latency = 0; - if (hcc != NULL) { - /* Must be master */ - connsm->conn_role = BLE_LL_CONN_ROLE_MASTER; - connsm->tx_win_size = BLE_LL_CONN_CFG_TX_WIN_SIZE; - connsm->tx_win_off = BLE_LL_CONN_CFG_TX_WIN_OFF; - connsm->master_sca = BLE_LL_CONN_CFG_MASTER_SCA; - - /* Hop increment is a random value between 5 and 16. */ - connsm->hop_inc = (rand() % 12) + 5; - - /* Set slave latency and supervision timeout */ - connsm->slave_latency = hcc->conn_latency; - connsm->supervision_tmo = hcc->supervision_timeout; - - /* Set own address type and peer address if needed */ - connsm->own_addr_type = hcc->own_addr_type; - if (hcc->filter_policy == 0) { - memcpy(&connsm->peer_addr, &hcc->peer_addr, BLE_DEV_ADDR_LEN); - connsm->peer_addr_type = hcc->peer_addr_type; - } - - /* XXX: for now, just make connection interval equal to max */ - connsm->conn_itvl = hcc->conn_itvl_max; - - /* Check the min/max CE lengths are less than connection interval */ - if (hcc->min_ce_len > (connsm->conn_itvl * 2)) { - connsm->min_ce_len = connsm->conn_itvl * 2; - } else { - connsm->min_ce_len = hcc->min_ce_len; - } - - if (hcc->max_ce_len > (connsm->conn_itvl * 2)) { - connsm->max_ce_len = connsm->conn_itvl * 2; - } else { - connsm->max_ce_len = hcc->max_ce_len; - } - - /* - * XXX: for now, just set the channel map to all 1's. Needs to get - * set to default or initialized or something - */ - connsm->num_used_chans = BLE_PHY_NUM_DATA_CHANS; - memset(connsm->chanmap, 0xff, BLE_LL_CONN_CHMAP_LEN - 1); - connsm->chanmap[4] = 0x1f; - - /* Calculate random access address and crc initialization value */ - connsm->access_addr = ble_ll_conn_calc_access_addr(); - connsm->crcinit = rand() & 0xffffff; - } else { - connsm->conn_role = BLE_LL_CONN_ROLE_SLAVE; - } - /* Initialize connection supervision timer */ cputime_timer_init(&connsm->conn_spvn_timer, ble_ll_conn_spvn_timer_cb, connsm); @@ -952,7 +961,7 @@ ble_ll_conn_sm_start(struct ble_ll_conn_sm *connsm, struct hci_create_conn *hcc) /* XXX: Controller notifies host of changes to effective tx/rx time/bytes*/ /* Add to list of active connections */ - SLIST_INSERT_HEAD(&g_ble_ll_conn_active_list, connsm, conn_sle); + SLIST_INSERT_HEAD(&g_ble_ll_conn_active_list, connsm, act_sle); } /** @@ -1016,7 +1025,7 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err) ble_ll_wfr_disable(); /* Remove from the active connection list */ - SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, conn_sle); + SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, act_sle); /* Free all packets on transmit queue */ while (1) { @@ -1028,8 +1037,9 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err) STAILQ_REMOVE_HEAD(&connsm->conn_txq, omp_next); m = (struct os_mbuf *)((uint8_t *)pkthdr - sizeof(struct os_mbuf)); - os_mbuf_free(m); - /* XXX: emtpy pdu? */ + if (m != (struct os_mbuf *)connsm->conn_empty_pdu) { + os_mbuf_free(m); + } } /* Make sure events off queue */ @@ -1046,7 +1056,7 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err) ble_ll_conn_comp_event_send(connsm, ble_err); /* Put connection state machine back on free list */ - STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, conn_stqe); + STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe); } /** @@ -1386,8 +1396,9 @@ ble_ll_conn_create(uint8_t *cmdbuf) return BLE_ERR_CONN_LIMIT; } - /* Start the connection sm */ - ble_ll_conn_sm_start(connsm, hcc); + /* Initialize state machine in master role and start state machine */ + ble_ll_conn_master_init(connsm, hcc); + ble_ll_conn_sm_start(connsm); /* Create the connection request */ ble_ll_conn_req_pdu_make(connsm); @@ -1395,8 +1406,8 @@ ble_ll_conn_create(uint8_t *cmdbuf) /* Start scanning */ rc = ble_ll_scan_initiator_start(hcc); if (rc) { - SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, conn_sle); - STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, conn_stqe); + SLIST_REMOVE(&g_ble_ll_conn_active_list,connsm,ble_ll_conn_sm,act_sle); + STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe); } else { /* Set the connection state machine we are trying to create. */ g_ble_ll_conn_create_sm = connsm; @@ -1447,6 +1458,7 @@ ble_ll_conn_is_peer_adv(uint8_t addr_type, uint8_t *adva) int rc; struct ble_ll_conn_sm *connsm; + /* XXX: Deal with different types of random addresses here! */ connsm = g_ble_ll_conn_create_sm; if (connsm && (connsm->peer_addr_type == addr_type) && !memcmp(adva, connsm->peer_addr, BLE_DEV_ADDR_LEN)) { @@ -1509,9 +1521,9 @@ ble_ll_init_rx_pdu_proc(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr) */ /* Get address type of advertiser */ if (rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK) { - addr_type = BLE_ADDR_TYPE_RANDOM; + addr_type = BLE_HCI_CONN_PEER_ADDR_RANDOM; } else { - addr_type = BLE_ADDR_TYPE_PUBLIC; + addr_type = BLE_HCI_CONN_PEER_ADDR_PUBLIC; } connsm->peer_addr_type = addr_type; @@ -1585,9 +1597,9 @@ ble_ll_init_rx_pdu_end(struct os_mbuf *rxpdu) /* Check filter policy */ adv_addr = rxbuf + BLE_LL_PDU_HDR_LEN; if (rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK) { - addr_type = BLE_ADDR_TYPE_RANDOM; + addr_type = BLE_HCI_CONN_PEER_ADDR_RANDOM; } else { - addr_type = BLE_ADDR_TYPE_PUBLIC; + addr_type = BLE_HCI_CONN_PEER_ADDR_PUBLIC; } /* Check filter policy */ @@ -1858,8 +1870,9 @@ ble_ll_conn_rx_pdu_end(struct os_mbuf *rxpdu, uint8_t crcok) if (pkthdr) { STAILQ_REMOVE_HEAD(&connsm->conn_txq, omp_next); txpdu = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); - os_mbuf_free(txpdu); - /* XXX: emtpy pdu? */ + if (txpdu != (struct os_mbuf *)connsm->conn_empty_pdu) { + os_mbuf_free(txpdu); + } } else { /* No packet on queue? This is an error! */ ++g_ble_ll_conn_stats.no_tx_pdu; @@ -1904,26 +1917,104 @@ ble_ll_conn_rx_pdu_end(struct os_mbuf *rxpdu, uint8_t crcok) } /** + * Data packet from host. + * + * Context: Link Layer task + * + * @param om + * @param handle + * @param length + * + * @return int + */ +void +ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t length) +{ + os_sr_t sr; + struct ble_mbuf_hdr *ble_hdr; + struct os_mbuf_pkthdr *pkthdr; + struct ble_ll_conn_sm *connsm; + uint16_t conn_handle; + uint16_t pb; + + /* See if we have an active matching connection handle */ + conn_handle = handle & 0x0FFF; + SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) { + if (connsm->conn_handle == conn_handle) { + /* Construct LL header in buffer */ + /* XXX: deal with length later */ + assert(length <= 251); + pb = handle & 0x3000; + if (pb == 0) { + om->om_data[0] = BLE_LL_LLID_DATA_START; + } else if (pb == 1) { + om->om_data[0] = BLE_LL_LLID_DATA_FRAG; + } else { + /* This should never happen! */ + break; + } + om->om_data[1] = (uint8_t)length; + + /* Clear flags field in BLE header */ + ble_hdr = BLE_MBUF_HDR_PTR(om); + ble_hdr->flags = 0; + + /* Add to transmit queue for the connection */ + pkthdr = OS_MBUF_PKTHDR(om); + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_TAIL(&connsm->conn_txq, pkthdr, omp_next); + OS_EXIT_CRITICAL(sr); + return; + } + } + + /* No connection found! */ + ++g_ble_ll_conn_stats.handle_not_found; + os_mbuf_free(om); +} + +/** * Called when a device has received a connect request while advertising and * the connect request has passed the advertising filter policy and is for - * us. This will start a connection in the slave role. + * us. This will start a connection in the slave role assuming that we dont + * already have a connection with this device and that the connect request + * parameters are valid. * * Context: Link Layer * - * @param rxbuf Pointer to received PDU + * @param rxbuf Pointer to received PDU + * + * @return 0: connection started. */ -void +int ble_ll_conn_slave_start(uint8_t *rxbuf) { uint32_t temp; uint32_t crcinit; + uint8_t *inita; uint8_t *dptr; + uint8_t addr_type; struct ble_ll_conn_sm *connsm; + /* Ignore the connection request if we are already connected*/ + inita = rxbuf + BLE_LL_PDU_HDR_LEN; + SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) { + if (!memcmp(&connsm->peer_addr, inita, BLE_DEV_ADDR_LEN)) { + if (rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK) { + addr_type = BLE_HCI_CONN_PEER_ADDR_RANDOM; + } else { + addr_type = BLE_HCI_CONN_PEER_ADDR_PUBLIC; + } + if (connsm->peer_addr_type == addr_type) { + return 0; + } + } + } + /* Allocate a connection. If none available, dont do anything */ connsm = ble_ll_conn_sm_get(); if (connsm == NULL) { - return; + return 0; } /* Set the pointer at the start of the connection data */ @@ -1978,9 +2069,9 @@ ble_ll_conn_slave_start(uint8_t *rxbuf) /* Set the address of device that we are connecting with */ memcpy(&connsm->peer_addr, rxbuf + BLE_LL_PDU_HDR_LEN, BLE_DEV_ADDR_LEN); if (rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK) { - connsm->peer_addr_type = BLE_ADDR_TYPE_RANDOM; + connsm->peer_addr_type = BLE_HCI_CONN_PEER_ADDR_RANDOM; } else { - connsm->peer_addr_type = BLE_ADDR_TYPE_PUBLIC; + connsm->peer_addr_type = BLE_HCI_CONN_PEER_ADDR_PUBLIC; } /* Calculate number of used channels; make sure it meets min requirement */ @@ -1990,17 +2081,18 @@ ble_ll_conn_slave_start(uint8_t *rxbuf) } /* Start the connection state machine */ - ble_ll_conn_sm_start(connsm, NULL); + connsm->conn_role = BLE_LL_CONN_ROLE_SLAVE; + ble_ll_conn_sm_start(connsm); /* The connection has been created. */ ble_ll_conn_created(connsm); - return; + return 1; err_slave_start: - STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, conn_stqe); + STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe); ++g_ble_ll_conn_stats.slave_rxd_bad_conn_req_params; - return; + return 0; } /* Initialize the connection module */ @@ -2033,6 +2125,7 @@ ble_ll_conn_init(void) connsm = (struct ble_ll_conn_sm *)os_memblock_get(&g_ble_ll_conn_pool); assert(connsm != NULL); connsm->conn_handle = i; + STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe); } /* Configure the global LL parameters */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b612bf4b/net/nimble/controller/src/ble_ll_hci.c ---------------------------------------------------------------------- diff --git a/net/nimble/controller/src/ble_ll_hci.c b/net/nimble/controller/src/ble_ll_hci.c index 98f9307..31cace8 100644 --- a/net/nimble/controller/src/ble_ll_hci.c +++ b/net/nimble/controller/src/ble_ll_hci.c @@ -376,6 +376,14 @@ ble_hci_transport_host_cmd_send(uint8_t *cmd) return 0; } +/* Send ACL data from host to contoller */ +int +ble_hci_transport_host_acl_data_send(struct os_mbuf *om) +{ + ble_ll_acl_data_in(om); + return 0; +} + /** * Initalize the LL HCI. */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b612bf4b/net/nimble/host/src/ble_hs.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/ble_hs.c b/net/nimble/host/src/ble_hs.c index f1a4fdc..8665ab4 100644 --- a/net/nimble/host/src/ble_hs.c +++ b/net/nimble/host/src/ble_hs.c @@ -32,7 +32,7 @@ #ifdef ARCH_sim #define BLE_HS_STACK_SIZE (1024) #else -#define BLE_HS_STACK_SIZE (128) +#define BLE_HS_STACK_SIZE (256) #endif struct os_task ble_hs_task; http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b612bf4b/net/nimble/host/src/host_dbg.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/host_dbg.c b/net/nimble/host/src/host_dbg.c index f2e1245..977f309 100644 --- a/net/nimble/host/src/host_dbg.c +++ b/net/nimble/host/src/host_dbg.c @@ -27,6 +27,7 @@ host_hci_dbg_le_event_disp(uint8_t subev, uint8_t len, uint8_t *evdata) { int8_t rssi; uint8_t advlen; + uint8_t status; int i; int imax; uint8_t *dptr; @@ -39,7 +40,7 @@ host_hci_dbg_le_event_disp(uint8_t subev, uint8_t len, uint8_t *evdata) rssi = evdata[10 + advlen]; console_printf("LE advertising report. len=%u num=%u evtype=%u " "addrtype=%u addr=%x.%x.%x.%x.%x.%x advlen=%u " - "rssi=%d", len, evdata[0], evdata[1], evdata[2], + "rssi=%d\n", len, evdata[0], evdata[1], evdata[2], evdata[8], evdata[7], evdata[6], evdata[5], evdata[4], evdata[3], advlen, rssi); if (advlen) { @@ -57,12 +58,28 @@ host_hci_dbg_le_event_disp(uint8_t subev, uint8_t len, uint8_t *evdata) ++dptr; } advlen -= imax; - console_printf("%s", adv_data_buf); + console_printf("%s\n", adv_data_buf); } } break; + case BLE_HCI_LE_SUBEV_CONN_COMPLETE: + status = evdata[0]; + if (status == BLE_ERR_SUCCESS) { + console_printf("LE connection complete. handle=%u role=%u " + "paddrtype=%u addr=%x.%x.%x.%x.%x.%x itvl=%u " + "latency=%u spvn_tmo=%u mca=%u\n", + le16toh(evdata + 1), evdata[3], evdata[4], + evdata[10], evdata[9], evdata[8], evdata[7], + evdata[6], evdata[5], + le16toh(evdata + 11), le16toh(evdata + 13), + evdata[14]); + } else { + console_printf("LE connection complete. FAIL (status=%u)\n",status); + } + break; + default: - console_printf("\tUnknown LE event"); + console_printf("\tUnknown LE event\n"); break; } } @@ -91,11 +108,26 @@ host_hci_dbg_cmd_complete_disp(uint8_t *evdata, uint8_t len) } } - console_printf("Command Complete: cmd_pkts=%u ocf=0x%x ogf=0x%x %s", + console_printf("Command Complete: cmd_pkts=%u ocf=0x%x ogf=0x%x %s\n", evdata[0], ocf, ogf, parmbuf); } void +host_hci_dbg_cmd_status_disp(uint8_t *evdata, uint8_t len) +{ + uint8_t ogf; + uint8_t ocf; + uint16_t opcode; + + opcode = le16toh(evdata + 2); + ogf = BLE_HCI_OGF(opcode); + ocf = BLE_HCI_OCF(opcode); + + console_printf("Command Status: status=%u cmd_pkts=%u ocf=0x%x ogf=0x%x\n", + evdata[0], evdata[1], ocf, ogf); +} + +void host_hci_dbg_event_disp(uint8_t *evbuf) { uint8_t *evdata; @@ -110,11 +142,14 @@ host_hci_dbg_event_disp(uint8_t *evbuf) case BLE_HCI_EVCODE_COMMAND_COMPLETE: host_hci_dbg_cmd_complete_disp(evdata, len); break; + case BLE_HCI_EVCODE_COMMAND_STATUS: + host_hci_dbg_cmd_status_disp(evdata, len); + break; case BLE_HCI_EVCODE_LE_META: host_hci_dbg_le_event_disp(evdata[0], len, evdata + 1); break; default: - console_printf("Unknown event 0x%x len=%u", evcode, len); + console_printf("Unknown event 0x%x len=%u\n", evcode, len); break; } } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b612bf4b/net/nimble/host/src/host_hci_cmd.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/host_hci_cmd.c b/net/nimble/host/src/host_hci_cmd.c index 5d28f62..0ea6799 100644 --- a/net/nimble/host/src/host_hci_cmd.c +++ b/net/nimble/host/src/host_hci_cmd.c @@ -47,7 +47,7 @@ host_hci_le_cmd_send(uint16_t ocf, uint8_t len, void *cmddata) uint16_t opcode; /* Don't allow multiple commands "in flight." */ - assert(host_hci_outstanding_opcode == 0); + //assert(host_hci_outstanding_opcode == 0); rc = -1; cmd = os_memblock_get(&g_hci_cmd_pool); http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b612bf4b/net/nimble/include/nimble/ble.h ---------------------------------------------------------------------- diff --git a/net/nimble/include/nimble/ble.h b/net/nimble/include/nimble/ble.h index 08339e5..13d26f2 100644 --- a/net/nimble/include/nimble/ble.h +++ b/net/nimble/include/nimble/ble.h @@ -72,14 +72,12 @@ struct ble_mbuf_hdr * * @return struct os_mbuf * */ -static inline void -ble_get_packet(struct os_mbuf *om) -{ - om = os_mbuf_get_pkthdr(&g_mbuf_pool, sizeof(struct ble_mbuf_hdr)); - if (om) { - om->om_data += 4; - } -} +#define ble_get_packet(__om) do { \ + __om = os_mbuf_get_pkthdr(&g_mbuf_pool, sizeof(struct ble_mbuf_hdr)); \ + if (__om) { \ + __om->om_data += 4; \ + } \ +} while (0) #define BLE_DEV_ADDR_LEN (6) extern uint8_t g_dev_addr[BLE_DEV_ADDR_LEN]; http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b612bf4b/net/nimble/include/nimble/hci_transport.h ---------------------------------------------------------------------- diff --git a/net/nimble/include/nimble/hci_transport.h b/net/nimble/include/nimble/hci_transport.h index 86587d7..f337930 100644 --- a/net/nimble/include/nimble/hci_transport.h +++ b/net/nimble/include/nimble/hci_transport.h @@ -23,4 +23,7 @@ int ble_hci_transport_host_cmd_send(uint8_t *cmd); /* Send a HCI event from the controller to the host */ int ble_hci_transport_ctlr_event_send(uint8_t *hci_ev); +/* Send ACL data from host to contoller */ +int ble_hci_transport_host_acl_data_send(struct os_mbuf *om); + #endif /* H_HCI_TRANSPORT_ */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b612bf4b/project/bletest/bletest.yml ---------------------------------------------------------------------- diff --git a/project/bletest/bletest.yml b/project/bletest/bletest.yml index c45dc08..82b0a37 100644 --- a/project/bletest/bletest.yml +++ b/project/bletest/bletest.yml @@ -4,3 +4,4 @@ project.eggs: - net/nimble/controller - net/nimble/host - libs/console/full + - libs/baselibc http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b612bf4b/project/bletest/src/main.c ---------------------------------------------------------------------- diff --git a/project/bletest/src/main.c b/project/bletest/src/main.c index 26b314b..78fd953 100755 --- a/project/bletest/src/main.c +++ b/project/bletest/src/main.c @@ -61,6 +61,7 @@ os_membuf_t g_mbuf_buffer[MBUF_MEMPOOL_SIZE]; /* Some application configurations */ #define BLETEST_ROLE_ADVERTISER (0) #define BLETEST_ROLE_SCANNER (1) +#define BLETEST_ROLE_INITIATOR (2) #define BLETEST_CFG_ROLE (BLETEST_ROLE_SCANNER) #define BLETEST_CFG_FILT_DUP_ADV (0) #define BLETEST_CFG_ADV_ITVL (500000 / BLE_HCI_ADV_ITVL) @@ -69,7 +70,13 @@ os_membuf_t g_mbuf_buffer[MBUF_MEMPOOL_SIZE]; #define BLETEST_CFG_SCAN_ITVL (700000 / BLE_HCI_SCAN_ITVL) #define BLETEST_CFG_SCAN_WINDOW (650000 / BLE_HCI_SCAN_ITVL) #define BLETEST_CFG_SCAN_TYPE (BLE_HCI_SCAN_TYPE_ACTIVE) -#define BLETEST_CFG_SCAN_FILT_POLICY (BLE_HCI_SCAN_FILT_USE_WL) +#define BLETEST_CFG_SCAN_FILT_POLICY (BLE_HCI_SCAN_FILT_NO_WL) +#define BLETEST_CFG_CONN_ITVL (1000) /* 1250 msecs */ +#define BLETEST_CFG_SLAVE_LATENCY (0) +#define BLETEST_CFG_INIT_FILTER_POLICY (BLE_HCI_CONN_FILT_NO_WL) +#define BLETEST_CFG_CONN_SPVN_TMO (1000) /* 10 seconds */ +#define BLETEST_CFG_MIN_CE_LEN (1000) +#define BLETEST_CFG_MAX_CE_LEN (BLETEST_CFG_CONN_ITVL * 2) /* BLETEST variables */ #define BLETEST_STACK_SIZE (256) @@ -182,6 +189,7 @@ bletest_init_advertising(void) assert(rc == 0); } +#if (BLETEST_CFG_ROLE == BLETEST_ROLE_SCANNER) void bletest_init_scanner(void) { @@ -210,6 +218,40 @@ bletest_init_scanner(void) assert(rc == 0); } } +#endif + +#if (BLETEST_CFG_ROLE == BLETEST_ROLE_INITIATOR) +void +bletest_init_initiator(void) +{ + int rc; + struct hci_create_conn cc; + struct hci_create_conn *hcc; + + /* Enable initiating */ + hcc = &cc; + hcc->conn_itvl_max = BLETEST_CFG_CONN_ITVL; + hcc->conn_itvl_min = BLETEST_CFG_CONN_ITVL; + hcc->conn_latency = BLETEST_CFG_SLAVE_LATENCY; + hcc->filter_policy = BLETEST_CFG_INIT_FILTER_POLICY; + hcc->supervision_timeout = BLETEST_CFG_CONN_SPVN_TMO; + hcc->scan_itvl = BLETEST_CFG_SCAN_ITVL; + hcc->scan_window = BLETEST_CFG_SCAN_WINDOW; + hcc->peer_addr_type = BLE_HCI_CONN_PEER_ADDR_PUBLIC; + hcc->peer_addr[0] = 0x00; + hcc->peer_addr[1] = 0x00; + hcc->peer_addr[2] = 0x00; + hcc->peer_addr[3] = 0x99; + hcc->peer_addr[4] = 0x99; + hcc->peer_addr[5] = 0x09; + hcc->own_addr_type = BLE_HCI_CONN_PEER_ADDR_PUBLIC; + hcc->min_ce_len = BLETEST_CFG_MIN_CE_LEN; + hcc->max_ce_len = BLETEST_CFG_MAX_CE_LEN; + + rc = host_hci_cmd_le_create_connection(hcc); + assert(rc == 0); +} +#endif void bletest_execute(void) @@ -246,6 +288,9 @@ bletest_execute(void) g_next_os_time += (OS_TICKS_PER_SEC * 60); } #endif +#if (BLETEST_CFG_ROLE == BLETEST_ROLE_INITIATOR) + (void)rc; +#endif } /** @@ -275,7 +320,7 @@ bletest_task_handler(void *arg) struct os_callout_func *cf; /* We are initialized */ - console_printf("Starting BLE test task"); + console_printf("Starting BLE test task\n"); /* Initialize eventq */ os_eventq_init(&g_bletest_evq); @@ -294,6 +339,11 @@ bletest_task_handler(void *arg) bletest_init_scanner(); #endif +#if (BLETEST_CFG_ROLE == BLETEST_ROLE_INITIATOR) + /* Initialize the scanner */ + bletest_init_initiator(); +#endif + /* Init bletest variables */ g_bletest_state = 0; g_next_os_time = os_time_get();