You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by we...@apache.org on 2016/01/19 01:14:58 UTC

[1/2] incubator-mynewt-larva git commit: Many changes to the scheduler and link layer to allow for scheduling of multiple connections. Also allows concurrent connections and/or advertising and/or scanning and/or initiating state machines

Repository: incubator-mynewt-larva
Updated Branches:
  refs/heads/master ccc970cd7 -> b6e2b5ffa


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/net/nimble/controller/src/ble_ll_scan.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_scan.c b/net/nimble/controller/src/ble_ll_scan.c
index c3ec3db..1b2ec0b 100644
--- a/net/nimble/controller/src/ble_ll_scan.c
+++ b/net/nimble/controller/src/ble_ll_scan.c
@@ -45,6 +45,11 @@
  * 3) Interleave sending scan requests to different advertisers? I guess I need 
  * a list of advertisers to which I sent a scan request and have yet to
  * receive a scan response from? Implement this.
+ * 
+ * 4) The current way I do things, it is possible that keep rescheduling the
+ * scanning item but never get a chance to execute it. This means that the
+ * last scan win start time could get really old. If we keep the current
+ * way of doing things we will need to address this issue.
  */
 
 /* The scanning state machine global object */
@@ -55,8 +60,7 @@ struct ble_ll_scan_stats
 {
     uint32_t scan_starts;
     uint32_t scan_stops;
-    uint32_t scan_win_misses;
-    uint32_t cant_set_sched;
+    uint32_t scan_event_misses;
     uint32_t scan_req_txf;
     uint32_t scan_req_txg;
 };
@@ -120,6 +124,46 @@ ble_ll_scan_req_backoff(struct ble_ll_scan_sm *scansm, int success)
 }
 
 /**
+ * Called to determine if we are inside or outside the scan window. If we 
+ * are inside the scan window it means that the device should be receiving 
+ * on the scan channel. 
+ * 
+ * Context: Interrupt and Link Layer
+ *  
+ * @param scansm 
+ * 
+ * @return int 0: inside scan window 1: outside scan window
+ */
+int
+ble_ll_scan_window_chk(struct ble_ll_scan_sm *scansm)
+{
+    int rc;
+    uint32_t now;
+    uint32_t itvl;
+
+    rc = 0;
+    itvl = cputime_usecs_to_ticks(scansm->scan_itvl * BLE_HCI_SCAN_ITVL);
+    now = cputime_get32();
+    while ((int32_t)(now - scansm->scan_win_start_time) >= itvl) {
+        scansm->scan_win_start_time += itvl;
+        ++scansm->scan_chan;
+        if (scansm->scan_chan == BLE_PHY_NUM_CHANS) {
+            scansm->scan_chan = BLE_PHY_ADV_CHAN_START;
+        }
+    }
+
+    if (scansm->scan_window != scansm->scan_itvl) {
+        itvl = cputime_usecs_to_ticks(scansm->scan_window * 
+                                      BLE_HCI_SCAN_ITVL);
+        if ((now - scansm->scan_win_start_time) >= itvl) {
+            rc = 1;
+        }
+    }
+
+    return rc;
+}
+
+/**
  * ble ll scan req pdu make
  *  
  * Construct a SCAN_REQ PDU. 
@@ -485,14 +529,6 @@ ble_ll_scan_chk_filter_policy(uint8_t pdu_type, uint8_t *rxbuf, uint8_t flags)
     return 0;
 }
 
-static int
-ble_ll_scan_win_end_cb(struct ble_ll_sched_item *sch)
-{
-    ble_phy_disable();
-    ble_ll_event_send(&g_ble_ll_scan_sm.scan_win_end_ev);
-    return BLE_LL_SCHED_STATE_DONE;
-}
-
 /**
  * Schedule callback for the start of a scan window 
  *  
@@ -503,43 +539,105 @@ ble_ll_scan_win_end_cb(struct ble_ll_sched_item *sch)
  * @return int 
  */
 static int
-ble_ll_scan_start_cb(struct ble_ll_sched_item *sch)
+ble_ll_scan_start(struct ble_ll_scan_sm *scansm)
 {
     int rc;
-    struct ble_ll_scan_sm *scansm;
-
-    /* Toggle the LED */
-    gpio_toggle(LED_BLINK_PIN);
-
-    /* Get the state machine for the event */
-    scansm = (struct ble_ll_scan_sm *)sch->cb_arg;
-
+    
     /* Set channel */
     rc = ble_phy_setchan(scansm->scan_chan, 0, 0);
     assert(rc == 0);
 
-    /* Set callbacks in case we transmit scan request or connect request */
+    /* 
+     * Set transmit end callback to NULL in case we transmit a scan request.
+     * There is a callback for the connect request.
+     */
     ble_phy_set_txend_cb(NULL, NULL);
 
     /* Start receiving */
     rc = ble_phy_rx();
     if (rc) {
-        /* Failure to go into receive. Just call the window end function */
-        ble_ll_event_send(&g_ble_ll_scan_sm.scan_win_end_ev);
         rc =  BLE_LL_SCHED_STATE_DONE;
     } else {
         /* Set link layer state to scanning */
-        if (g_ble_ll_scan_sm.scan_type == BLE_SCAN_TYPE_INITIATE) {
+        if (scansm->scan_type == BLE_SCAN_TYPE_INITIATE) {
             ble_ll_state_set(BLE_LL_STATE_INITIATING);
         } else {
             ble_ll_state_set(BLE_LL_STATE_SCANNING);
         }
 
         /* Set end time to end of scan window */
-        sch->next_wakeup = sch->end_time;
-        sch->sched_cb = ble_ll_scan_win_end_cb;
         rc = BLE_LL_SCHED_STATE_RUNNING;
     }
+    scansm->last_sched_time = cputime_get32();
+
+    /* If there is a still a scan response pending, we have failed! */
+    if (scansm->scan_rsp_pending) {
+        ble_ll_scan_req_backoff(scansm, 0);
+    }
+
+    return rc;
+}
+
+/**
+ * Called when the scanning schedule item executes
+ *  
+ * Context: Interrupt 
+ * 
+ * @param sch 
+ * 
+ * @return int 
+ */
+int
+ble_ll_scan_sched_cb(struct ble_ll_sched_item *sch)
+{
+    int rc;
+    struct ble_ll_scan_sm *scansm;
+
+    /* 
+     * If we are not in the standby state it means that the scheduled
+     * scanning event was overlapped in the schedule. In this case all we do
+     * is post the scan schedule end event.
+     */
+    switch (ble_ll_state_get()) {
+    case BLE_LL_STATE_ADV:
+    case BLE_LL_STATE_CONNECTION:
+        rc = -1;
+        break;
+    case BLE_LL_STATE_INITIATING:
+    case BLE_LL_STATE_SCANNING:
+        /* Must disable PHY since we will move to a new channel */
+        ble_phy_disable();
+        rc = 0;
+        break;
+    case BLE_LL_STATE_STANDBY:
+        rc = 0;
+        break;
+    default:
+        rc = 0;
+        assert(0);
+        break;
+    }
+
+    scansm = (struct ble_ll_scan_sm *)sch->cb_arg;
+    if (rc) {
+        rc =  BLE_LL_SCHED_STATE_DONE;
+    } else {
+        /* Determine if we should be off or receiving */
+        rc = ble_ll_scan_window_chk(scansm);
+        if (!rc) {
+            ble_ll_scan_start(scansm);
+            rc = BLE_LL_SCHED_STATE_RUNNING;
+        } else {
+            rc =  BLE_LL_SCHED_STATE_DONE;
+        }
+    }
+
+    if (rc == BLE_LL_SCHED_STATE_DONE) {
+        scansm->last_sched_time = cputime_get32();
+    }
+
+    /* Post scanning scheduled done event */
+    ble_ll_event_send(&scansm->scan_sched_ev);
 
     return rc;
 }
@@ -548,10 +646,15 @@ ble_ll_scan_start_cb(struct ble_ll_sched_item *sch)
  * Stop the scanning state machine 
  */
 void
-ble_ll_scan_sm_stop(struct ble_ll_scan_sm *scansm, int conn_created)
+ble_ll_scan_sm_stop(int chk_disable)
 {
+    os_sr_t sr;
+    uint8_t lls;
+    struct ble_ll_scan_sm *scansm;
+
     /* Remove any scheduled advertising items */
-    ble_ll_sched_rmv(BLE_LL_SCHED_TYPE_SCAN, NULL);
+    scansm = &g_ble_ll_scan_sm;
+    ble_ll_sched_rmv_elem(&scansm->scan_sch);
 
     /* Disable scanning state machine */
     scansm->scan_enabled = 0;
@@ -559,57 +662,28 @@ ble_ll_scan_sm_stop(struct ble_ll_scan_sm *scansm, int conn_created)
     /* Count # of times stopped */
     ++g_ble_ll_scan_stats.scan_stops;
 
-    /* Only set state if we are current in a scan window */
-    if ((g_ble_ll_data.ll_state == BLE_LL_STATE_SCANNING) ||
-        (g_ble_ll_data.ll_state == BLE_LL_STATE_INITIATING)) {
-        /* Disable the PHY */
-        if (!conn_created) {
+    /* Only set state if we are currently in a scan window */
+    if (chk_disable) {
+        OS_ENTER_CRITICAL(sr);
+        lls = ble_ll_state_get();
+        if ((lls == BLE_LL_STATE_SCANNING) || (lls == BLE_LL_STATE_INITIATING)) {
+            /* Disable phy */
             ble_phy_disable();
-        }
-
-        /* Disable whitelisting  */
-        ble_ll_whitelist_disable();
-
-        /* Set LL state to standby */
-        ble_ll_state_set(BLE_LL_STATE_STANDBY);
-    }
-}
 
-static struct ble_ll_sched_item *
-ble_ll_scan_sched_set(struct ble_ll_scan_sm *scansm)
-{
-    int rc;
-    struct ble_ll_sched_item *sch;
+            /* Disable whitelisting  */
+            ble_ll_whitelist_disable();
 
-    sch = ble_ll_sched_get_item();
-    if (sch) {
-        /* Set sched type */
-        sch->sched_type = BLE_LL_SCHED_TYPE_SCAN;
-
-        /* Set the start time of the event */
-        sch->start_time = scansm->scan_win_start_time - 
-            cputime_usecs_to_ticks(XCVR_RX_SCHED_DELAY_USECS);
-
-        /* Set the callback, arg, start and end time */
-        sch->cb_arg = scansm;
-        sch->sched_cb = ble_ll_scan_start_cb;
-        sch->end_time = scansm->scan_win_start_time + 
-            cputime_usecs_to_ticks(scansm->scan_window * BLE_HCI_SCAN_ITVL);
-
-        /* XXX: for now, we cant get an overlap so assert on error. */
-        /* Add the item to the scheduler */
-        rc = ble_ll_sched_add(sch);
-        assert(rc == 0);
-    } else {
-        ++g_ble_ll_scan_stats.cant_set_sched;
+            /* Set LL state to standby */
+            ble_ll_state_set(BLE_LL_STATE_STANDBY);
+        }
+        OS_EXIT_CRITICAL(sr);
     }
-
-    return sch;
 }
 
 static int
 ble_ll_scan_sm_start(struct ble_ll_scan_sm *scansm)
 {
+    os_sr_t sr;
     struct ble_ll_sched_item *sch;
 
     /* 
@@ -650,73 +724,74 @@ ble_ll_scan_sm_start(struct ble_ll_scan_sm *scansm)
     scansm->backoff_count = 1;
     scansm->scan_rsp_pending = 0;
 
+    /* Set schedule elements */
+    sch = &scansm->scan_sch;
+    sch->sched_type = BLE_LL_SCHED_TYPE_SCAN;
+    sch->cb_arg = scansm;
+    sch->sched_cb = ble_ll_scan_sched_cb;
+
+    /* XXX: align to current or next slot???. */
     /* Schedule start time now */
     scansm->scan_win_start_time = cputime_get32();
 
-    /* Set packet in schedule */
-    sch = ble_ll_scan_sched_set(scansm);
-    if (!sch) {
-        /* XXX: set a wakeup timer to deal with this. For now, assert */
-        assert(0);
+    /* 
+     * If we are in standby, start scanning. Otherwise, scanning will resume
+     * when the currently scheduled event ends.
+     */ 
+    OS_ENTER_CRITICAL(sr);
+    if (ble_ll_state_get() == BLE_LL_STATE_STANDBY) {
+        ble_ll_scan_start(scansm);
     }
+    OS_EXIT_CRITICAL(sr);
+
+    /* Post scanning scheduled done event */
+    ble_ll_event_send(&scansm->scan_sched_ev);
 
     return BLE_ERR_SUCCESS;
 }
 
 void
-ble_ll_scan_win_end_proc(void *arg)
+ble_ll_scan_event_proc(void *arg)
 {
-    int32_t delta_t;
+    uint32_t now;
+    uint32_t scan_win_start;
     uint32_t itvl;
     uint32_t win_ticks;
     struct ble_ll_scan_sm *scansm;
+    struct ble_ll_sched_item *sch;
 
-    /* Toggle the LED */
-    gpio_toggle(LED_BLINK_PIN);
-
-    /* We are no longer scanning  */
     scansm = (struct ble_ll_scan_sm *)arg;
-    ble_ll_state_set(BLE_LL_STATE_STANDBY);
+    sch = &scansm->scan_sch;
 
-    /* Move to next channel */
-    ++scansm->scan_chan;
-    if (scansm->scan_chan == BLE_PHY_NUM_CHANS) {
-        scansm->scan_chan = BLE_PHY_ADV_CHAN_START;
-    }
+    assert((int32_t)(scansm->last_sched_time-scansm->scan_win_start_time) >= 0);
 
-    /* If there is a scan response pending, it means we failed a scan req */
-    if (scansm->scan_rsp_pending) {
-        ble_ll_scan_req_backoff(scansm, 0);
-    }
-
-    /* Calculate # of ticks per scan window */
-    win_ticks = cputime_usecs_to_ticks(scansm->scan_window * BLE_HCI_SCAN_ITVL);
-
-    /* Set next scan window start time */
     itvl = cputime_usecs_to_ticks(scansm->scan_itvl * BLE_HCI_SCAN_ITVL);
-    scansm->scan_win_start_time += itvl;
-      
-    /* Set next scanning window start. */        
-    delta_t = (int32_t)(cputime_get32() - scansm->scan_win_start_time);
-    while (delta_t >= (int32_t)win_ticks) {
-        /* 
-         * Since it is possible to scan continuously, it is possible
-         * that we will be late here if the scan window is equal to the
-         * scan interval (or very close). So what we will do here is only
-         * increment a stat if we missed a scan window
-         */
-        /* Count times we were late */
-        ++g_ble_ll_scan_stats.scan_win_misses;
+    scan_win_start = scansm->scan_win_start_time;
+    while ((int32_t)(scansm->last_sched_time - scan_win_start) >= itvl) {
+        scan_win_start += itvl;
+    }
 
-        /* Calculate start time of next scan windowe */
-        scansm->scan_win_start_time += itvl;
-        delta_t -= (int32_t)itvl;
+    /* Determine what the next scheduled scanning item should be. */
+    if (scansm->scan_window == scansm->scan_itvl) {
+        scan_win_start += itvl;
+    } else {
+        win_ticks = cputime_usecs_to_ticks(scansm->scan_window * BLE_HCI_SCAN_ITVL);
+        if ((scansm->last_sched_time - scansm->scan_win_start_time) < win_ticks) {
+            scan_win_start += win_ticks;
+        } else {
+            scan_win_start += itvl;
+        }
     }
 
-    if (!ble_ll_scan_sched_set(scansm)) {
-        /* XXX: we will need to set a timer here to wake us up */
-        assert(0);
+    now = cputime_get32();
+    if ((int32_t)(now - scan_win_start) <= 0) {
+        sch->start_time = scan_win_start;
+    } else {
+        ++g_ble_ll_scan_stats.scan_event_misses;
+        sch->start_time = now;
     }
+    sch->end_time = sch->start_time;
+    ble_ll_sched_scan(sch);
 }
 
 /**
@@ -734,7 +809,7 @@ ble_ll_scan_win_end_proc(void *arg)
  *  1: we may send a response to this frame.
  */
 int
-ble_ll_scan_rx_pdu_start(uint8_t pdu_type, struct os_mbuf *rxpdu)
+ble_ll_scan_rx_isr_start(uint8_t pdu_type, struct os_mbuf *rxpdu)
 {
     int rc;
     struct ble_ll_scan_sm *scansm;
@@ -762,6 +837,9 @@ ble_ll_scan_rx_pdu_start(uint8_t pdu_type, struct os_mbuf *rxpdu)
             ble_hdr = BLE_MBUF_HDR_PTR(rxpdu);
             ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_SCAN_RSP_CHK;
         }
+
+        /* Disable wfr if running */
+        ble_ll_wfr_disable();
         break;
     case BLE_SCAN_TYPE_PASSIVE:
     default:
@@ -784,7 +862,7 @@ ble_ll_scan_rx_pdu_start(uint8_t pdu_type, struct os_mbuf *rxpdu)
  *       > 0: Do not disable PHY as that has already been done.
  */
 int
-ble_ll_scan_rx_pdu_end(struct os_mbuf *rxpdu)
+ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok)
 {
     int rc;
     int chk_send_req;
@@ -796,9 +874,29 @@ ble_ll_scan_rx_pdu_end(struct os_mbuf *rxpdu)
     struct ble_mbuf_hdr *ble_hdr;
     struct ble_ll_scan_sm *scansm;
 
-    /* If passively scanning return (with -1) since no scan request is sent */
+    /* Get scanning state machine */
     scansm = &g_ble_ll_scan_sm;
 
+    /* 
+     * The reason we do something different here (as opposed to failed CRC) is
+     * that the received PDU will not be handed up in this case. So we have
+     * to restart scanning and handle a failed scan request. Note that we
+     * return 0 in this case because we dont want the phy disabled.
+     */
+    if (rxpdu == NULL) {
+        if (scansm->scan_rsp_pending) {
+            ble_ll_scan_req_backoff(scansm, 0);
+        }
+        ble_phy_rx();
+        return 0;
+    }
+
+    /* Just leave if the CRC is not OK. */
+    rc = -1;
+    if (!crcok) {
+        goto scan_rx_isr_exit;
+    }
+
     /* Get pdu type, pointer to address and address "type"  */
     rxbuf = rxpdu->om_data;
     pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK;
@@ -839,7 +937,6 @@ ble_ll_scan_rx_pdu_end(struct os_mbuf *rxpdu)
     }
 
     /* Should we send a scan request? */
-    rc = -1;
     if (chk_send_req) {
         /* 
          * Check to see if we have received a scan response from this
@@ -865,29 +962,44 @@ ble_ll_scan_rx_pdu_end(struct os_mbuf *rxpdu)
         }
     }
 
+scan_rx_isr_exit:
+    if (rc) {
+        ble_ll_state_set(BLE_LL_STATE_STANDBY);
+    }
     return rc;
 }
 
 /**
- * Called to resume scanning, usually after a packet has been received 
- * while in the scanning or inititating state.
+ * Called to resume scanning. This is called after an advertising event or 
+ * connection event has ended. It is also called if we receive a packet while 
+ * in the initiating or scanning state. 
+ *  
+ * Context: Link Layer task 
  */
 void
-ble_ll_scan_resume(void)
+ble_ll_scan_chk_resume(void)
 {
-    /* We need to re-enable the PHY if we are in idle state */
-    if (ble_phy_state_get() == BLE_PHY_STATE_IDLE) {
-        if (ble_phy_rx()) {
-            /* If we fail, we will end the current scan window. */
-            ble_ll_sched_rmv(BLE_LL_SCHED_TYPE_SCAN, NULL);
-            ble_ll_event_send(&g_ble_ll_scan_sm.scan_win_end_ev);
+    os_sr_t sr;
+    struct ble_ll_scan_sm *scansm;
+
+    scansm = &g_ble_ll_scan_sm;
+    if (scansm->scan_enabled) {
+        OS_ENTER_CRITICAL(sr);
+        if (ble_ll_state_get() == BLE_LL_STATE_STANDBY) {
+            if (!ble_ll_scan_window_chk(scansm)) {
+                /* Turn on the receiver and set state */
+                ble_ll_scan_start(scansm);
+            }
         }
+        OS_EXIT_CRITICAL(sr);
     }
 }
 
 /**
  * Called when the wait for response timer expires while in the scanning 
  * state. 
+ *  
+ * Context: Interrupt. 
  */
 void
 ble_ll_scan_wfr_timer_exp(void)
@@ -898,14 +1010,13 @@ ble_ll_scan_wfr_timer_exp(void)
 
     /* 
      * If we timed out waiting for a response, the scan response pending
-     * flag should be set. Deal with scan backoff.
+     * flag should be set. Deal with scan backoff. Put device back into rx.
      */ 
     scansm = &g_ble_ll_scan_sm;
     if (scansm->scan_rsp_pending) {
         ble_ll_scan_req_backoff(scansm, 0);
     }
-    
-    ble_ll_scan_resume();
+    ble_phy_rx();
 }
 
 /**
@@ -931,7 +1042,7 @@ ble_ll_scan_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf, struct ble_mbuf_hdr *hdr)
     scan_rsp_chk = hdr->rxinfo.flags & BLE_MBUF_HDR_F_SCAN_RSP_CHK;
 
     /* We dont care about scan requests or connect requests */
-    if ((!hdr->rxinfo.crcok) || (ptype == BLE_ADV_PDU_TYPE_SCAN_REQ) || 
+    if (!BLE_MBUF_HDR_CRC_OK(hdr) || (ptype == BLE_ADV_PDU_TYPE_SCAN_REQ) ||
         (ptype == BLE_ADV_PDU_TYPE_CONNECT_REQ)) {
         goto scan_continue;
     }
@@ -994,9 +1105,10 @@ scan_continue:
      * pending flag if we received a valid response
      */
     if (scansm->scan_rsp_pending && scan_rsp_chk) {
-        ble_ll_scan_req_backoff(scansm, 1);
+        ble_ll_scan_req_backoff(scansm, 0);
     }
-    ble_ll_scan_resume();
+
+    ble_ll_scan_chk_resume();
     return;
 }
 
@@ -1095,7 +1207,7 @@ ble_ll_scan_set_enable(uint8_t *cmd)
         }
     } else {
         if (scansm->scan_enabled) {
-            ble_ll_scan_sm_stop(scansm, 0);
+            ble_ll_scan_sm_stop(1);
         }
     }
 
@@ -1184,7 +1296,7 @@ ble_ll_scan_reset(void)
     /* If enabled, stop it. */
     scansm = &g_ble_ll_scan_sm;
     if (scansm->scan_enabled) {
-        ble_ll_scan_sm_stop(scansm, 0);
+        ble_ll_scan_sm_stop(0);
     }
 
     /* Reset all statistics */
@@ -1220,8 +1332,8 @@ ble_ll_scan_init(void)
     memset(scansm, 0, sizeof(struct ble_ll_scan_sm));
 
     /* Initialize scanning window end event */
-    scansm->scan_win_end_ev.ev_type = BLE_LL_EVENT_SCAN_WIN_END;
-    scansm->scan_win_end_ev.ev_arg = scansm;
+    scansm->scan_sched_ev.ev_type = BLE_LL_EVENT_SCAN;
+    scansm->scan_sched_ev.ev_arg = scansm;
 
     /* Set all non-zero default parameters */
     scansm->scan_itvl = BLE_HCI_SCAN_ITVL_DEF;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/net/nimble/controller/src/ble_ll_sched.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_sched.c b/net/nimble/controller/src/ble_ll_sched.c
index e131dff..9a639f1 100644
--- a/net/nimble/controller/src/ble_ll_sched.c
+++ b/net/nimble/controller/src/ble_ll_sched.c
@@ -20,119 +20,542 @@
 #include "controller/ble_phy.h"
 #include "controller/ble_ll.h"
 #include "controller/ble_ll_sched.h"
+#include "controller/ble_ll_adv.h"
+#include "controller/ble_ll_scan.h"
+#include "ble_ll_conn_priv.h"
 #include "hal/hal_cputime.h"
 
 /* XXX: this is temporary. Not sure what I want to do here */
 struct cpu_timer g_ble_ll_sched_timer;
 
 /* XXX: TODO:
- *  1) Add a "priority" scheme possibly. This would allow items to be
- *  added if they overlapped.
- *  2) Add some accounting to the schedule code to see how late we are
+ *  1) Add some accounting to the schedule code to see how late we are
  *  (min/max?)
+ * 
+ *  2) Need to determine how we really want to handle the case when we execute
+ *  a schedule item but there is a current event. We could:
+ *      -> Reschedule the schedule item and let current event finish
+ *      -> Kill the current event and run the scheduled item.
+ *      -> Disable schedule timer while in an event; could cause us to be late.
+ *      -> Wait for current event to finish hoping it does before schedule item. 
  */
-#define BLE_LL_CFG_SCHED_ITEMS      (8)
-#define BLE_LL_SCHED_POOL_SIZE      \
-    OS_MEMPOOL_SIZE(BLE_LL_CFG_SCHED_ITEMS, sizeof(struct ble_ll_sched_item))
-
-struct os_mempool g_ble_ll_sched_pool;
-os_membuf_t g_ble_ll_sched_mem[BLE_LL_SCHED_POOL_SIZE];
 
 /* Queue for timers */
 TAILQ_HEAD(ll_sched_qhead, ble_ll_sched_item) g_ble_ll_sched_q;
 
 /**
- * Executes a schedule item by calling the schedule callback function.
+ * Checks if two events in the schedule will overlap in time. NOTE: consecutive 
+ * schedule items can end and start at the same time. 
  * 
- * @param sch Pointer to schedule item
+ * @param s1 
+ * @param s2 
  * 
- * @return int 0: schedule item is not over; otherwise schedule item is done.
+ * @return int 
  */
-int
-ble_ll_sched_execute(struct ble_ll_sched_item *sch)
+static int
+ble_ll_sched_is_overlap(struct ble_ll_sched_item *s1, 
+                        struct ble_ll_sched_item *s2)
 {
     int rc;
 
-    assert(sch->sched_cb);
-    rc = sch->sched_cb(sch);
+    rc = 1;
+    if ((int32_t)(s1->start_time - s2->start_time) < 0) {
+        /* Make sure this event does not overlap current event */
+        if ((int32_t)(s1->end_time - s2->start_time) <= 0) {
+            rc = 0;
+        }
+    } else {
+        /* Check for overlap */
+        if ((int32_t)(s1->start_time - s2->end_time) >= 0) {
+            rc = 0;
+        }
+    }
+
     return rc;
 }
 
-
 /**
- * Allocate a schedule item
+ * Checks if the scheduled item 'sch' overlaps the scanning schedule item 
+ * 'scan'. If so, the scanning scheduled item is removed and we post the 
+ * scan event so that we can reschedule the next scanning opportunity. 
  * 
- * @return struct ble_ll_sched_item* 
+ * 
+ * @param scan 
+ * @param sch 
  */
-struct ble_ll_sched_item *
-ble_ll_sched_get_item(void)
+static void
+ble_ll_sched_chk_scan_overlap(struct ble_ll_sched_item *scan, 
+                              struct ble_ll_sched_item *sch)
 {
-    struct ble_ll_sched_item *sch;
+    struct ble_ll_scan_sm *scansm;
 
-    sch = os_memblock_get(&g_ble_ll_sched_pool);
-    if (sch) {
-        memset(sch, 0, sizeof(struct ble_ll_sched_item));
+    if (ble_ll_sched_is_overlap(scan, sch)) {
+        scansm = (struct ble_ll_scan_sm *)scan->cb_arg;
+        ble_ll_event_send(&scansm->scan_sched_ev);
+        TAILQ_REMOVE(&g_ble_ll_sched_q, scan, link);
+        scan->enqueued = 0;
     }
-    return sch;
 }
 
-/**
- * Free a schedule item
- * 
- * @param sch 
+/* 
+ * Determines if the schedule item overlaps the currently running schedule
+ * item. We only care about connection schedule items
  */
-void
-ble_ll_sched_free_item(struct ble_ll_sched_item *sch)
+int
+ble_ll_sched_overlaps_current(struct ble_ll_sched_item *sch)
 {
-    os_error_t err;
-    err = os_memblock_put(&g_ble_ll_sched_pool, sch);
-    assert(err == OS_OK);
+    int rc;
+    uint32_t ce_end_time;
+
+    rc = 0;
+    if (ble_ll_state_get() == BLE_LL_STATE_CONNECTION) {
+        ce_end_time = ble_ll_conn_get_ce_end_time();
+        if ((int32_t)(ce_end_time - sch->start_time) > 0) {
+            rc = 1;
+        }
+    }
+    return rc;
+}
+
+static int
+ble_ll_sched_conn_overlap(struct ble_ll_sched_item *entry)
+{
+    int rc;
+    struct ble_ll_conn_sm *connsm;
+
+    /* Should only be advertising or a connection here */
+    if (entry->sched_type == BLE_LL_SCHED_TYPE_CONN) {
+        connsm = (struct ble_ll_conn_sm *)entry->cb_arg;
+        entry->enqueued = 0;
+        TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link);
+        ble_ll_event_send(&connsm->conn_ev_end);
+        rc = 0;
+    } else {
+        rc = -1;
+    }
+
+    return rc;
+}
+
+struct ble_ll_sched_item *
+ble_ll_sched_insert_if_empty(struct ble_ll_sched_item *sch)
+{
+    struct ble_ll_sched_item *entry;
+
+    entry = TAILQ_FIRST(&g_ble_ll_sched_q);
+    if (!entry) {
+        TAILQ_INSERT_HEAD(&g_ble_ll_sched_q, sch, link);
+        sch->enqueued = 1;
+    }
+    return entry;
 }
 
-/**
- * Add a schedule item to the schedule list
- * 
- * @param sch 
- * 
- * @return int 
- */
 int
-ble_ll_sched_add(struct ble_ll_sched_item *sch)
+ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm)
 {
     int rc;
     os_sr_t sr;
+    uint32_t usecs;
+    struct ble_ll_sched_item *sch;
+    struct ble_ll_sched_item *start_overlap;
+    struct ble_ll_sched_item *end_overlap;
     struct ble_ll_sched_item *entry;
+    struct ble_ll_conn_sm *tmp;
+    struct ble_ll_scan_sm *scansm;
+
+    /* Get schedule element from connection */
+    sch = &connsm->conn_sch;
+
+    /* Set schedule start and end times */
+    if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+        usecs = XCVR_RX_SCHED_DELAY_USECS;
+        usecs += connsm->slave_cur_window_widening;
+    } else {
+        usecs = XCVR_TX_SCHED_DELAY_USECS; 
+    }
+    sch->start_time = connsm->anchor_point - cputime_usecs_to_ticks(usecs);
+    sch->end_time = connsm->ce_end_time;
+
+    /* Better be past current time or we just leave */
+    if ((int32_t)(sch->start_time - cputime_get32()) < 0) {
+        return -1;
+    }
 
-    /* Determine if we are able to add this to the schedule */
+    /* We have to find a place for this schedule */
     OS_ENTER_CRITICAL(sr);
 
+    if (ble_ll_sched_overlaps_current(sch)) {
+        OS_EXIT_CRITICAL(sr);
+        return -1;
+    }
+
+    /* Stop timer since we will add an element */
+    cputime_timer_stop(&g_ble_ll_sched_timer);
+
+    start_overlap = NULL;
+    end_overlap = NULL;
     rc = 0;
-    if (TAILQ_EMPTY(&g_ble_ll_sched_q)) {
-        TAILQ_INSERT_HEAD(&g_ble_ll_sched_q, sch, link);
+    TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) {
+        if (ble_ll_sched_is_overlap(sch, entry)) {
+            /* Only insert if this element is older than all that we overlap */
+            if ((entry->sched_type != BLE_LL_SCHED_TYPE_SCAN) &&
+                ((entry->sched_type == BLE_LL_SCHED_TYPE_ADV) ||
+                 !ble_ll_conn_is_lru((struct ble_ll_conn_sm *)sch->cb_arg, 
+                                     (struct ble_ll_conn_sm *)entry->cb_arg))) {
+                start_overlap = NULL;
+                rc = -1;
+                break;
+            }
+            if (start_overlap == NULL) {
+                start_overlap = entry;
+                end_overlap = entry;
+            } else {
+                end_overlap = entry;
+            }
+        } else {
+            if ((int32_t)(sch->end_time - entry->start_time) < 0) {
+                rc = 0;
+                TAILQ_INSERT_BEFORE(entry, sch, link);
+                break;
+            }
+        }
+    }
+
+    if (!rc) {
+        if (!entry) {
+            TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link);
+        }
+        sch->enqueued = 1;
+    }
+
+    /* Remove first to last scheduled elements */
+    entry = start_overlap;
+    while (entry) {
+        start_overlap = TAILQ_NEXT(entry,link);
+        if (entry->sched_type == BLE_LL_SCHED_TYPE_CONN) {
+            tmp = (struct ble_ll_conn_sm *)entry->cb_arg;
+            ble_ll_event_send(&tmp->conn_ev_end);
+        } else {
+            scansm = (struct ble_ll_scan_sm *)entry->cb_arg;
+            ble_ll_event_send(&scansm->scan_sched_ev);
+        }
+
+        TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link);
+        entry->enqueued = 0;
+
+        if (entry == end_overlap) {
+            break;
+        }
+        entry = start_overlap;
+    }
+
+    /* Get first on list */
+    sch = TAILQ_FIRST(&g_ble_ll_sched_q);
+
+    OS_EXIT_CRITICAL(sr);
+
+    /* Restart timer */
+    cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
+
+    return rc;
+}
+
+int
+ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, uint32_t adv_rxend, 
+                        uint8_t req_slots)
+{
+    int rc;
+    os_sr_t sr;
+    uint32_t initial_start;
+    uint32_t earliest_start;
+    uint32_t earliest_end;
+    uint32_t dur;
+    uint32_t itvl_t;
+    uint32_t ce_end_time;
+    struct ble_ll_sched_item *entry;
+    struct ble_ll_sched_item *sch;
+    struct ble_ll_sched_item *scan;
+
+    /* Better have a connsm */
+    assert(connsm != NULL);
+
+    /* Assume no scheduled item is a scanning item */
+    scan = NULL;
+
+    /* Get schedule element from connection */
+    rc = -1;
+    sch = &connsm->conn_sch;
+
+    /* 
+     * The earliest start time is 1.25 msecs from the end of the connect
+     * request transmission. Note that adv_rxend is the end of the received
+     * advertisement, so we need to add an IFS plus the time it takes to send
+     * the connection request
+     */
+    dur = cputime_usecs_to_ticks(req_slots * BLE_LL_SCHED_USECS_PER_SLOT);
+    earliest_start = adv_rxend + 
+        cputime_usecs_to_ticks(BLE_LL_IFS + BLE_LL_CONN_REQ_DURATION +
+                               BLE_LL_CONN_INITIAL_OFFSET);
+    earliest_end = earliest_start + dur;
+
+    itvl_t = cputime_usecs_to_ticks(connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS);
+
+    /* We have to find a place for this schedule */
+    OS_ENTER_CRITICAL(sr);
+
+    /* The schedule item must occur after current running item (if any) */
+    sch->start_time = earliest_start;
+
+    /*
+     * If we are currently in a connection, we add one slot time to the
+     * earliest start so we can end the connection reasonably.
+     */
+    if (ble_ll_state_get() == BLE_LL_STATE_CONNECTION) {
+        ce_end_time = ble_ll_conn_get_ce_end_time();
+        if ((int32_t)(ce_end_time - sch->start_time) >= 0) {
+            earliest_start = ce_end_time;
+            earliest_end = earliest_start + dur;
+        }
+    }
+    initial_start = earliest_start;
+
+    if (!ble_ll_sched_insert_if_empty(sch)) {
+        /* Nothing in schedule. Schedule as soon as possible */
+        rc = 0;
+        connsm->tx_win_off = 0;
     } else {
         cputime_timer_stop(&g_ble_ll_sched_timer);
         TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) {
-            if ((int32_t)(sch->start_time - entry->start_time) < 0) {
-                /* Make sure this event does not overlap current event */
+            /* Ignore scan/initiate types */
+            if (entry->sched_type == BLE_LL_SCHED_TYPE_SCAN) {
+                scan = entry;
+                continue;
+            }
+
+            /* Set these because the overlap function needs them to be set */
+            sch->start_time = earliest_start;
+            sch->end_time = earliest_end;
+
+            /* Check for overlapping events */
+            if (ble_ll_sched_is_overlap(sch, entry)) {
+                /* Earliest start is end of this event since we overlap */
+                earliest_start = entry->end_time;
+                earliest_end = earliest_start + dur;
+            } else {
+                /* We can insert if before entry in list */
+                if ((int32_t)(sch->end_time - entry->start_time) < 0) {
+                    if ((earliest_start - initial_start) <= itvl_t) {
+                        rc = 0;
+                        TAILQ_INSERT_BEFORE(entry, sch, link);
+                    }
+                    break;
+                }
+            }
+        }
+
+        if (!entry) {
+            if ((earliest_start - initial_start) <= itvl_t) {
+                rc = 0;
+                TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link);
+            }
+        }
+
+        if (!rc) {
+            /* calculate number of connection intervals before start */
+            sch->enqueued = 1;
+            connsm->tx_win_off = (earliest_start - initial_start) /
+                cputime_usecs_to_ticks(BLE_LL_CONN_ITVL_USECS);
+        }
+
+        /* Restart with head of list */
+        sch = TAILQ_FIRST(&g_ble_ll_sched_q);
+    }
+
+    if (!rc) {
+        sch->start_time = earliest_start;
+        sch->end_time = earliest_end;
+        connsm->anchor_point = earliest_start +
+            cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+        connsm->ce_end_time = earliest_end; 
+
+        /* 
+         * If there was a scanning item it is possible that the order of the
+         * scanning item and the newly added connection are incorrect. So,
+         * we check for overlap and if there is one, we reschedule the
+         * scanning item
+         */
+        if (scan) {
+            ble_ll_sched_chk_scan_overlap(scan, sch);
+        }
+    }
+
+    OS_EXIT_CRITICAL(sr);
+
+    cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
+
+    return rc;
+}
+
+int
+ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm)
+{
+    int rc;
+    os_sr_t sr;
+    struct ble_ll_sched_item *entry;
+    struct ble_ll_sched_item *next_sch;
+    struct ble_ll_sched_item *sch;
+    struct ble_ll_sched_item *scan;
+
+    /* Get schedule element from connection */
+    rc = -1;
+    sch = &connsm->conn_sch;
+
+    /* Set schedule start and end times */
+    sch->start_time = connsm->anchor_point -  
+        cputime_usecs_to_ticks(XCVR_RX_SCHED_DELAY_USECS + 
+                               connsm->slave_cur_window_widening);
+    sch->end_time = connsm->ce_end_time;
+
+    /* We have to find a place for this schedule */
+    OS_ENTER_CRITICAL(sr);
+
+    /* The schedule item must occur after current running item (if any) */
+    if (ble_ll_sched_overlaps_current(sch)) {
+        OS_EXIT_CRITICAL(sr);
+        return rc;
+    }
+
+    entry = ble_ll_sched_insert_if_empty(sch);
+    if (!entry) {
+        /* Nothing in schedule. Schedule as soon as possible */
+        rc = 0;
+    } else {
+        scan = NULL;
+        cputime_timer_stop(&g_ble_ll_sched_timer);
+        while (1) {
+            /* Skip scanning schedule items */
+            if (entry->sched_type == BLE_LL_SCHED_TYPE_SCAN) {
+                scan = entry;
+                continue;
+            }
+
+            next_sch = entry->link.tqe_next;
+            if (ble_ll_sched_is_overlap(sch, entry)) {
+                if (ble_ll_sched_conn_overlap(entry)) {
+                    break;
+                }
+            } else {
                 if ((int32_t)(sch->end_time - entry->start_time) < 0) {
-                    TAILQ_INSERT_BEFORE(entry, sch, link);   
-                } else {
-                    rc = BLE_LL_SCHED_ERR_OVERLAP;
+                    rc = 0;
+                    TAILQ_INSERT_BEFORE(entry, sch, link);
+                    break;
                 }
+            }
+
+            /* Move to next entry */
+            entry = next_sch;
+
+            /* Insert at tail if none left to check */
+            if (!entry) {
+                rc = 0;
+                TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link);
                 break;
+            }
+        }
+
+        if (!rc) {
+            sch->enqueued = 1;
+            if (scan) {
+                ble_ll_sched_chk_scan_overlap(scan, sch);
+            }
+        }
+        sch = TAILQ_FIRST(&g_ble_ll_sched_q);
+    }
+
+    OS_EXIT_CRITICAL(sr);
+
+    cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
+
+    return rc;
+}
+
+int
+ble_ll_sched_adv_new(struct ble_ll_sched_item *sch)
+{
+    int rc;
+    os_sr_t sr;
+    uint32_t ce_end_time;
+    uint32_t adv_start;
+    uint32_t duration;
+    struct ble_ll_sched_item *entry;
+    struct ble_ll_sched_item *scan;
+
+    /* Get length of schedule item */
+    duration = sch->end_time - sch->start_time;
+
+    OS_ENTER_CRITICAL(sr);
+
+    /*
+     * If we are currently in a connection, we add one slot time to the
+     * earliest start so we can end the connection reasonably.
+     */
+    if (ble_ll_state_get() == BLE_LL_STATE_CONNECTION) {
+        sch->start_time += cputime_usecs_to_ticks(BLE_LL_SCHED_USECS_PER_SLOT);
+        ce_end_time = ble_ll_conn_get_ce_end_time();
+        if ((int32_t)(ce_end_time - sch->start_time) >= 0) {
+            sch->start_time = ce_end_time;
+        }
+        sch->end_time = sch->start_time + duration;
+    }
+
+    entry = ble_ll_sched_insert_if_empty(sch);
+    if (!entry) {
+        rc = 0;
+        adv_start = sch->start_time;
+    } else {
+        scan = NULL;
+        cputime_timer_stop(&g_ble_ll_sched_timer);
+        TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) {
+            /* Ignore scan/initiate types */
+            if (entry->sched_type == BLE_LL_SCHED_TYPE_SCAN) {
+                scan = entry;
+                continue;
+            }
+
+            /* Check for overlapping events */
+            if (ble_ll_sched_is_overlap(sch, entry)) {
+                /* Earliest start is end of this event since we overlap */
+                sch->start_time = entry->end_time;
+                sch->end_time = sch->start_time + duration;
             } else {
-                /* Check for overlap */
-                if ((int32_t)(sch->start_time - entry->end_time) < 0) {
-                    rc = BLE_LL_SCHED_ERR_OVERLAP;
+                /* We can insert if before entry in list */
+                if ((int32_t)(sch->end_time - entry->start_time) < 0) {
+                    rc = 0;
+                    TAILQ_INSERT_BEFORE(entry, sch, link);
                     break;
                 }
             }
         }
+
         if (!entry) {
+            rc = 0;
             TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link);
         }
+        adv_start = sch->start_time;
+
+        if (!rc) {
+            sch->enqueued = 1;
+            if (scan) {
+                ble_ll_sched_chk_scan_overlap(scan, sch);
+            }
+        }
+
+        /* Restart with head of list */
+        sch = TAILQ_FIRST(&g_ble_ll_sched_q);
     }
 
+    ble_ll_adv_scheduled(adv_start);
+
     OS_EXIT_CRITICAL(sr);
 
     cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
@@ -140,49 +563,198 @@ ble_ll_sched_add(struct ble_ll_sched_item *sch)
     return rc;
 }
 
-/**
- * Remove a schedule item. You can use this function to: 
- *  1) Remove all schedule items of type 'sched_type' (cb_arg = NULL)
- *  2) Remove schedule items of type 'sched_type' and matching callback args
- * 
- * 
- * @param sched_type 
- * 
- * @return int 
- */
 int
-ble_ll_sched_rmv(uint8_t sched_type, void *cb_arg)
+ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch)
 {
+    int rc;
     os_sr_t sr;
     struct ble_ll_sched_item *entry;
-    struct ble_ll_sched_item *next;
+    struct ble_ll_sched_item *next_sch;
+    struct ble_ll_sched_item *scan;
 
     OS_ENTER_CRITICAL(sr);
 
-    entry = TAILQ_FIRST(&g_ble_ll_sched_q);
-    if (entry) {
+    /* The schedule item must occur after current running item (if any) */
+    if (ble_ll_sched_overlaps_current(sch)) {
+        OS_EXIT_CRITICAL(sr);
+        return -1;
+    }
+
+    entry = ble_ll_sched_insert_if_empty(sch);
+    if (!entry) {
+        /* Nothing in schedule. Schedule as soon as possible */
+        rc = 0;
+    } else {
+        scan = NULL;
         cputime_timer_stop(&g_ble_ll_sched_timer);
-        while (entry) {
-            next = TAILQ_NEXT(entry, link);
-            if (entry->sched_type == sched_type) {
-                if ((cb_arg == NULL) || (cb_arg == entry->cb_arg)) {
-                    TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link);
-                    os_memblock_put(&g_ble_ll_sched_pool, entry);
+        while (1) {
+            /* Skip scanning schedule items */
+            if (entry->sched_type == BLE_LL_SCHED_TYPE_SCAN) {
+                scan = entry;
+                continue;
+            }
+
+            next_sch = entry->link.tqe_next;
+            if (ble_ll_sched_is_overlap(sch, entry)) {
+                if (ble_ll_sched_conn_overlap(entry)) {
+                    assert(0);
+                }
+            } else {
+                if ((int32_t)(sch->end_time - entry->start_time) < 0) {
+                    rc = 0;
+                    TAILQ_INSERT_BEFORE(entry, sch, link);
+                    break;
                 }
-            } 
-            entry = next;
+            }
+
+            /* Move to next entry */
+            entry = next_sch;
+
+            /* Insert at tail if none left to check */
+            if (!entry) {
+                rc = 0;
+                TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link);
+                break;
+            }
         }
 
-        /* Start the timer if there is an item */
-        entry = TAILQ_FIRST(&g_ble_ll_sched_q);
-        if (entry) {
-            cputime_timer_start(&g_ble_ll_sched_timer, entry->start_time);
+        if (!rc) {
+            sch->enqueued = 1;
+            if (scan) {
+                ble_ll_sched_chk_scan_overlap(scan, sch);
+            }
         }
+
+        sch = TAILQ_FIRST(&g_ble_ll_sched_q);
     }
 
     OS_EXIT_CRITICAL(sr);
 
-    return 0;
+    cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
+
+    return rc;
+}
+
+void
+ble_ll_sched_scan(struct ble_ll_sched_item *sch)
+{
+    int insert_head;
+    os_sr_t sr;
+    struct ble_ll_sched_item *entry;
+
+    OS_ENTER_CRITICAL(sr);
+
+    entry = ble_ll_sched_insert_if_empty(sch);
+    if (!entry) {
+        insert_head = 1;
+    } else {
+        TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) {
+            /* No need to worry about overlap. */
+            if ((int32_t)(sch->start_time - entry->start_time) < 0) {
+                TAILQ_INSERT_BEFORE(entry, sch, link);
+                break;
+            }
+        }
+
+        insert_head = 0;
+        if (!entry) {
+            TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link);
+        } else {
+            if (sch == TAILQ_FIRST(&g_ble_ll_sched_q)) {
+                cputime_timer_stop(&g_ble_ll_sched_timer);
+                insert_head = 1;
+            }
+        }
+        sch->enqueued = 1;
+    }
+
+    OS_EXIT_CRITICAL(sr);
+
+    if (insert_head) {
+        cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
+    }
+}
+
+/**
+ * Remove a schedule element
+ * 
+ * @param sched_type 
+ * 
+ * @return int 
+ */
+void
+ble_ll_sched_rmv_elem(struct ble_ll_sched_item *sch)
+{
+    os_sr_t sr;
+    struct ble_ll_sched_item *first;
+
+    if (!sch) {
+        return;
+    }
+
+    OS_ENTER_CRITICAL(sr);
+    if (sch->enqueued) {
+        first = TAILQ_FIRST(&g_ble_ll_sched_q);
+        if (first == sch) {
+            cputime_timer_stop(&g_ble_ll_sched_timer);
+        }
+
+        TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link);
+        sch->enqueued = 0;
+
+        if (first == sch) {
+            first = TAILQ_FIRST(&g_ble_ll_sched_q);
+            if (first) {
+                cputime_timer_start(&g_ble_ll_sched_timer, first->start_time);
+            }
+        }
+    }
+    OS_EXIT_CRITICAL(sr);
+}
+
+/**
+ * Executes a schedule item by calling the schedule callback function.
+ * 
+ * @param sch Pointer to schedule item
+ * 
+ * @return int 0: schedule item is not over; otherwise schedule item is done.
+ */
+static int
+ble_ll_sched_execute_item(struct ble_ll_sched_item *sch)
+{
+    int rc;
+    uint8_t lls;
+
+    /* 
+     * Scanning items are special. If this is one, just call the callback.
+     * If we are doing something else the callback will handle it.
+     */ 
+    if (sch->sched_type != BLE_LL_SCHED_TYPE_SCAN) {
+        /* 
+         * This is either an advertising event or connection event start. If
+         * we are scanning or initiating just stop it.
+         */
+        lls = ble_ll_state_get();
+        if (lls != BLE_LL_STATE_STANDBY) {
+            /* We have to disable the PHY no matter what */
+            ble_phy_disable();
+            ble_ll_wfr_disable();
+            if ((lls == BLE_LL_STATE_SCANNING) || 
+                (lls == BLE_LL_STATE_INITIATING)) {
+                ble_ll_state_set(BLE_LL_STATE_STANDBY);
+            } else if (lls == BLE_LL_STATE_ADV) {
+                ++g_ble_ll_stats.sched_state_adv_errs;
+                ble_ll_adv_halt();
+            } else {
+                ble_ll_conn_event_halt();
+                ++g_ble_ll_stats.sched_state_conn_errs;
+            }
+        }
+    }
+
+    assert(sch->sched_cb);
+    rc = sch->sched_cb(sch);
+    return rc;
 }
 
 /**
@@ -195,23 +767,16 @@ ble_ll_sched_rmv(uint8_t sched_type, void *cb_arg)
 void
 ble_ll_sched_run(void *arg)
 {
-    int rc;
     struct ble_ll_sched_item *sch;
 
     /* Look through schedule queue */
     while ((sch = TAILQ_FIRST(&g_ble_ll_sched_q)) != NULL) {
         /* Make sure we have passed the start time of the first event */
         if ((int32_t)(cputime_get32() - sch->start_time) >= 0) {
-            /* Execute the schedule item */
-            rc = ble_ll_sched_execute(sch);
-            if (rc) {
-                TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link);
-                os_memblock_put(&g_ble_ll_sched_pool, sch);
-            } else {
-                /* Event is not over; schedule next wakeup time */
-                cputime_timer_start(&g_ble_ll_sched_timer, sch->next_wakeup);
-                break;
-            }
+            /* Execute the schedule item and remove it when done */
+            ble_ll_sched_execute_item(sch);
+            TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link);
+            sch->enqueued = 0;
         } else {
             cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
             break;
@@ -220,6 +785,17 @@ ble_ll_sched_run(void *arg)
 }
 
 /**
+ * Stop the scheduler
+ *  
+ * Context: Link Layer task 
+ */
+void
+ble_ll_sched_stop(void)
+{
+    cputime_timer_stop(&g_ble_ll_sched_timer);
+}
+
+/**
  * Initialize the scheduler. Should only be called once and should be called 
  * before any of the scheduler API are called. 
  * 
@@ -228,15 +804,7 @@ ble_ll_sched_run(void *arg)
 int
 ble_ll_sched_init(void)
 {
-    os_error_t err;
-
-    err = os_mempool_init(&g_ble_ll_sched_pool, BLE_LL_CFG_SCHED_ITEMS, 
-                          sizeof(struct ble_ll_sched_item), 
-                          g_ble_ll_sched_mem, "ll_sched");
-    assert(err == OS_OK);
-
     /* Initialize cputimer for the scheduler */
     cputime_timer_init(&g_ble_ll_sched_timer, ble_ll_sched_run, NULL);
-
-    return err;
+    return 0;
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/net/nimble/drivers/native/src/ble_phy.c
----------------------------------------------------------------------
diff --git a/net/nimble/drivers/native/src/ble_phy.c b/net/nimble/drivers/native/src/ble_phy.c
index 9a39c5c..cf0a154 100644
--- a/net/nimble/drivers/native/src/ble_phy.c
+++ b/net/nimble/drivers/native/src/ble_phy.c
@@ -41,6 +41,7 @@ struct ble_phy_statistics
 {
     uint32_t tx_good;
     uint32_t tx_fail;
+    uint32_t tx_late;
     uint32_t tx_bytes;
     uint32_t rx_starts;
     uint32_t rx_aborts;
@@ -118,6 +119,7 @@ void
 ble_phy_isr(void)
 {
     int rc;
+    uint8_t crcok;
     uint8_t transition;
     uint32_t irq_en;
     struct os_mbuf *rxpdu;
@@ -180,19 +182,20 @@ ble_phy_isr(void)
         ble_hdr->rxinfo.flags = 0;
         ble_hdr->rxinfo.rssi = -77;    /* XXX: dummy rssi */
         ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan;
-        ble_hdr->rxinfo.crcok = 1;
 
         /* Count PHY crc errors and valid packets */
-        if (ble_hdr->rxinfo.crcok == 0) {
+        crcok = 1;
+        if (!crcok) {
             ++g_ble_phy_stats.rx_crc_err;
         } else {
             ++g_ble_phy_stats.rx_valid;
+            ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CRC_OK;
         }
 
         /* Call Link Layer receive payload function */
         rxpdu = g_ble_phy_data.rxpdu;
         g_ble_phy_data.rxpdu = NULL;
-        rc = ble_ll_rx_end(rxpdu,ble_hdr->rxinfo.channel,ble_hdr->rxinfo.crcok);
+        rc = ble_ll_rx_end(rxpdu, ble_hdr);
         if (rc < 0) {
             /* Disable the PHY. */
             ble_phy_disable();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/net/nimble/drivers/nrf52/src/ble_phy.c
----------------------------------------------------------------------
diff --git a/net/nimble/drivers/nrf52/src/ble_phy.c b/net/nimble/drivers/nrf52/src/ble_phy.c
index a12336c..90463a6 100644
--- a/net/nimble/drivers/nrf52/src/ble_phy.c
+++ b/net/nimble/drivers/nrf52/src/ble_phy.c
@@ -23,6 +23,8 @@
 #include "controller/ble_ll.h"
 #include "mcu/nrf52_bitfields.h"
 
+/* XXX: 4) Make sure RF is higher priority interrupt than schedule */
+
 /* To disable all radio interrupts */
 #define NRF52_RADIO_IRQ_MASK_ALL    (0x34FF)
 
@@ -154,6 +156,7 @@ ble_phy_isr(void)
 {
     int rc;
     uint8_t transition;
+    uint8_t crcok;
     uint32_t irq_en;
     uint32_t state;
     uint32_t wfr_time;
@@ -163,13 +166,14 @@ ble_phy_isr(void)
     /* Read irq register to determine which interrupts are enabled */
     irq_en = NRF_RADIO->INTENCLR;
 
-    ble_ll_log(BLE_LL_LOG_ID_PHY_ISR, 0, 0, irq_en);
-
     /* Check for disabled event. This only happens for transmits now */
     if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) {
         /* Better be in TX state! */
         assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX);
 
+        ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, g_ble_phy_txrx_buf[1], 0, 
+                   NRF_TIMER0->CC[2]);
+
         /* Clear events and clear interrupt on disabled event */
         NRF_RADIO->EVENTS_DISABLED = 0;
         NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk;
@@ -249,10 +253,11 @@ ble_phy_isr(void)
             }
         }
 
-        /* Initialize flags and channel in ble header at rx start */
+        /* Initialize flags, channel and state in ble header at rx start */
         ble_hdr = BLE_MBUF_HDR_PTR(g_ble_phy_data.rxpdu);
-        ble_hdr->rxinfo.flags = 0;
+        ble_hdr->rxinfo.flags = ble_ll_state_get();
         ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan;
+        ble_hdr->rxinfo.handle = 0;
 
         /* Call Link Layer receive start function */
         rc = ble_ll_rx_start(g_ble_phy_data.rxpdu, g_ble_phy_data.phy_chan);
@@ -291,21 +296,21 @@ ble_phy_isr(void)
         ble_hdr = BLE_MBUF_HDR_PTR(g_ble_phy_data.rxpdu);
         assert(NRF_RADIO->EVENTS_RSSIEND != 0);
         ble_hdr->rxinfo.rssi = -1 * NRF_RADIO->RSSISAMPLE;
-        ble_hdr->rxinfo.crcok = (uint8_t)NRF_RADIO->CRCSTATUS;
         ble_hdr->end_cputime = NRF_TIMER0->CC[2];
 
         /* Count PHY crc errors and valid packets */
-        if (ble_hdr->rxinfo.crcok == 0) {
+        crcok = (uint8_t)NRF_RADIO->CRCSTATUS;
+        if (!crcok) {
             ++g_ble_phy_stats.rx_crc_err;
         } else {
             ++g_ble_phy_stats.rx_valid;
+            ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CRC_OK;
         }
 
         /* Call Link Layer receive payload function */
         rxpdu = g_ble_phy_data.rxpdu;
         g_ble_phy_data.rxpdu = NULL;
-        rc = ble_ll_rx_end(rxpdu, ble_hdr->rxinfo.channel, 
-                           ble_hdr->rxinfo.crcok);
+        rc = ble_ll_rx_end(rxpdu, ble_hdr);
         if (rc < 0) {
             /* Disable the PHY. */
             ble_phy_disable();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/net/nimble/include/nimble/ble.h
----------------------------------------------------------------------
diff --git a/net/nimble/include/nimble/ble.h b/net/nimble/include/nimble/ble.h
index 170d6f4..bcb9ff5 100644
--- a/net/nimble/include/nimble/ble.h
+++ b/net/nimble/include/nimble/ble.h
@@ -47,7 +47,7 @@ struct ble_mbuf_hdr_rxinfo
 {
     uint8_t flags;
     uint8_t channel;
-    uint8_t crcok;
+    uint8_t handle;
     int8_t rssi;
 };
 
@@ -68,14 +68,24 @@ struct ble_mbuf_hdr
     uint32_t end_cputime;
 };
 
-/* Flag definitions. Apply to both txinfo and rxinfo */
-#define BLE_MBUF_HDR_F_DEVMATCH         (0x01)
-#define BLE_MBUF_HDR_F_CONN_REQ_TXD     (0x02)
-#define BLE_MBUF_HDR_F_TXD              (0x04)
-#define BLE_MBUF_HDR_F_SCAN_RSP_TXD     (0x08)
-#define BLE_MBUF_HDR_F_SCAN_RSP_CHK     (0x10)
+/* Flag definitions for rxinfo  */
+#define BLE_MBUF_HDR_F_CRC_OK           (0x80)
+#define BLE_MBUF_HDR_F_DEVMATCH         (0x40)
+#define BLE_MBUF_HDR_F_CONN_REQ_TXD     (0x20)
+#define BLE_MBUF_HDR_F_SCAN_RSP_TXD     (0x10)
+#define BLE_MBUF_HDR_F_SCAN_RSP_CHK     (0x08)
+#define BLE_MBUF_HDR_F_RXSTATE_MASK     (0x07)      
 
-#define BLE_MBUF_HDR_PTR(om)    \
+/* Flag definitions for txinfo */
+#define BLE_MBUF_HDR_F_TXD              (0x01)
+
+#define BLE_MBUF_HDR_CRC_OK(hdr)    \
+    ((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_CRC_OK)
+
+#define BLE_MBUF_HDR_RX_STATE(hdr)  \
+    ((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_RXSTATE_MASK)
+
+#define BLE_MBUF_HDR_PTR(om)        \
     (struct ble_mbuf_hdr *)((uint8_t *)om + sizeof(struct os_mbuf) + \
                             sizeof(struct os_mbuf_pkthdr))
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/project/bletest/src/main.c
----------------------------------------------------------------------
diff --git a/project/bletest/src/main.c b/project/bletest/src/main.c
index 48555a3..a3c1466 100755
--- a/project/bletest/src/main.c
+++ b/project/bletest/src/main.c
@@ -30,6 +30,8 @@
 #include "controller/ble_ll.h"
 #include "controller/ble_ll_hci.h"
 #include "controller/ble_ll_conn.h"
+#include "controller/ble_ll_scan.h"
+#include "controller/ble_ll_adv.h"
 
 /* Init all tasks */
 volatile int tasks_initialized;
@@ -51,7 +53,7 @@ uint8_t g_host_adv_data[BLE_HCI_MAX_ADV_DATA_LEN];
 uint8_t g_host_adv_len;
 
 /* Create a mbuf pool of BLE mbufs */
-#define MBUF_NUM_MBUFS      (16)
+#define MBUF_NUM_MBUFS      (20)
 #define MBUF_BUF_SIZE       \
     ((BLE_LL_CFG_ACL_DATA_PKT_LEN + sizeof(struct hci_data_hdr) + 3) & 0xFFFC)
 #define MBUF_MEMBLOCK_SIZE  (MBUF_BUF_SIZE + BLE_MBUF_PKT_OVERHEAD)
@@ -66,23 +68,25 @@ os_membuf_t g_mbuf_buffer[MBUF_MEMPOOL_SIZE];
 #define BLETEST_ROLE_ADVERTISER         (0)
 #define BLETEST_ROLE_SCANNER            (1)
 #define BLETEST_ROLE_INITIATOR          (2)
-#define BLETEST_CFG_ROLE                (BLETEST_ROLE_INITIATOR)
+#define BLETEST_CFG_ROLE                (BLETEST_ROLE_ADVERTISER)
 #define BLETEST_CFG_FILT_DUP_ADV        (0)
-#define BLETEST_CFG_ADV_ITVL            (500000 / BLE_HCI_ADV_ITVL)
+#define BLETEST_CFG_ADV_ITVL            (60000 / BLE_HCI_ADV_ITVL)
 #define BLETEST_CFG_ADV_TYPE            BLE_HCI_ADV_TYPE_ADV_IND
 #define BLETEST_CFG_ADV_FILT_POLICY     (BLE_HCI_ADV_FILT_NONE)
 #define BLETEST_CFG_SCAN_ITVL           (700000 / BLE_HCI_SCAN_ITVL)
-#define BLETEST_CFG_SCAN_WINDOW         (650000 / BLE_HCI_SCAN_ITVL)
+#define BLETEST_CFG_SCAN_WINDOW         (700000 / BLE_HCI_SCAN_ITVL)
 #define BLETEST_CFG_SCAN_TYPE           (BLE_HCI_SCAN_TYPE_ACTIVE)
 #define BLETEST_CFG_SCAN_FILT_POLICY    (BLE_HCI_SCAN_FILT_NO_WL)
-#define BLETEST_CFG_CONN_ITVL           (1000)  /* 1250 msecs */           
+#define BLETEST_CFG_CONN_ITVL           (1000)  /* in 1.25 msec increments */           
 #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)
+#define BLETEST_CFG_MIN_CE_LEN          (6)    
+#define BLETEST_CFG_MAX_CE_LEN          (BLETEST_CFG_CONN_ITVL)
+#define BLETEST_CFG_CONCURRENT_CONNS    (8)
 
 /* BLETEST variables */
+#define BLETEST_PKT_SIZE                (128)
 #define BLETEST_STACK_SIZE              (256)
 #define BLETEST_TASK_PRIO               (HOST_TASK_PRIO + 1)
 uint32_t g_next_os_time;
@@ -92,8 +96,11 @@ struct os_callout_func g_bletest_timer;
 struct os_task bletest_task;
 os_stack_t bletest_stack[BLETEST_STACK_SIZE];
 uint32_t g_bletest_conn_end;
-#define BLETEST_PKT_SIZE                (128)
+uint8_t g_bletest_current_conns;
+uint8_t g_bletest_cur_peer_addr[BLE_DEV_ADDR_LEN];
+uint8_t g_last_handle_used;
 
+#if 0
 void
 bletest_inc_adv_pkt_num(void)
 {
@@ -121,6 +128,13 @@ bletest_inc_adv_pkt_num(void)
         host_hci_outstanding_opcode = 0;
     }
 }
+#else
+void
+bletest_inc_adv_pkt_num(void)
+{
+    return;
+}
+#endif
 
 /**
  * Sets the advertising data to be sent in advertising pdu's which contain
@@ -173,6 +187,7 @@ bletest_set_adv_data(uint8_t *dptr)
     return len;
 }
 
+#if (BLETEST_CFG_ROLE == BLETEST_ROLE_ADVERTISER)
 void
 bletest_init_advertising(void)
 {
@@ -180,6 +195,9 @@ bletest_init_advertising(void)
     uint8_t adv_len;
     struct hci_adv_params adv;
 
+    /* Just zero out advertising */
+    memset(&adv, 0, sizeof(struct hci_adv_params));
+
     /* Set advertising parameters */
     adv.adv_type = BLETEST_CFG_ADV_TYPE;
     adv.adv_channel_map = 0x07;
@@ -188,22 +206,21 @@ bletest_init_advertising(void)
     adv.peer_addr_type = BLE_HCI_ADV_PEER_ADDR_PUBLIC;
     if ((adv.adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) ||
         (adv.adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD)) {
-        adv.peer_addr[0] = 0x00;
-        adv.peer_addr[1] = 0x00;
-        adv.peer_addr[2] = 0x00;
-        adv.peer_addr[3] = 0x99;
-        adv.peer_addr[4] = 0x99;
-        adv.peer_addr[5] = 0x09;
+        memcpy(adv.peer_addr, g_bletest_cur_peer_addr, BLE_DEV_ADDR_LEN);
         adv_len = 0;
     } else {
         adv_len = bletest_set_adv_data(&g_host_adv_data[0]);
     }
 
+    console_printf("Trying to connect to %x.%x.%x.%x.%x.%x\n",
+                   adv.peer_addr[0], adv.peer_addr[1], adv.peer_addr[2],
+                   adv.peer_addr[3], adv.peer_addr[4], adv.peer_addr[5]);
+
     if (adv.adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) {
         adv.adv_itvl_min = 0;
         adv.adv_itvl_max = 0;
     } else {
-        adv.adv_itvl_min = BLE_HCI_ADV_ITVL_NONCONN_MIN;
+        adv.adv_itvl_min = BLETEST_CFG_ADV_ITVL;
         adv.adv_itvl_max = BLETEST_CFG_ADV_ITVL; /* Advertising interval */
     }
 
@@ -224,6 +241,7 @@ bletest_init_advertising(void)
         host_hci_outstanding_opcode = 0;
     }
 }
+#endif
 
 #if (BLETEST_CFG_ROLE == BLETEST_ROLE_SCANNER)
 void
@@ -256,6 +274,28 @@ bletest_init_scanner(void)
         host_hci_outstanding_opcode = 0;
     }
 }
+
+void
+bletest_execute(void)
+{
+    int rc;
+
+    /* Enable scanning */
+    if ((int32_t)(os_time_get() - g_next_os_time) >= 0) {
+        if (g_bletest_state) {
+            rc = host_hci_cmd_le_set_scan_enable(0, BLETEST_CFG_FILT_DUP_ADV);
+            assert(rc == 0);
+            host_hci_outstanding_opcode = 0;
+            g_bletest_state = 0;
+        } else {
+            rc = host_hci_cmd_le_set_scan_enable(1, BLETEST_CFG_FILT_DUP_ADV);
+            assert(rc == 0);
+            host_hci_outstanding_opcode = 0;
+            g_bletest_state = 1;
+        }
+        g_next_os_time += (OS_TICKS_PER_SEC * 60);
+    }
+}
 #endif
 
 #if (BLETEST_CFG_ROLE == BLETEST_ROLE_INITIATOR)
@@ -276,20 +316,48 @@ bletest_init_initiator(void)
     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] = 0x88;
-    hcc->peer_addr[4] = 0x88;
-    hcc->peer_addr[5] = 0x08;
+    memcpy(hcc->peer_addr, g_bletest_cur_peer_addr, BLE_DEV_ADDR_LEN);
     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;
 
+    console_printf("Trying to connect to %x.%x.%x.%x.%x.%x\n",
+                   hcc->peer_addr[0], hcc->peer_addr[1], hcc->peer_addr[2],
+                   hcc->peer_addr[3], hcc->peer_addr[4], hcc->peer_addr[5]);
+
     rc = host_hci_cmd_le_create_connection(hcc);
     assert(rc == 0);
     host_hci_outstanding_opcode = 0;
 }
+
+void
+bletest_execute(void)
+{
+    uint16_t handle;
+
+    /* 
+     * Determine if there is an active connection for the current handle
+     * we are trying to create. If so, start looking for the next one
+     */
+    if (g_bletest_current_conns < BLETEST_CFG_CONCURRENT_CONNS) {
+        handle = g_bletest_current_conns + 1;
+        if (ble_ll_conn_find_active_conn(handle)) {
+            /* Scanning better be stopped! */
+            assert(ble_ll_scan_enabled() == 0);
+
+            /* Add to current connections */
+            ++g_bletest_current_conns;
+
+            /* Move to next connection */
+            if (g_bletest_current_conns < BLETEST_CFG_CONCURRENT_CONNS) {
+                /* restart initiating */
+                g_bletest_cur_peer_addr[5] += 1;
+                g_dev_addr[5] += 1;
+                bletest_init_initiator();
+            }
+        }
+    }
+}
 #endif
 
 #if (BLETEST_CFG_ROLE == BLETEST_ROLE_ADVERTISER)
@@ -303,19 +371,18 @@ bletest_get_packet(void)
     struct os_mbuf *om;
 
     om = NULL;
-    if (g_mbuf_pool.omp_pool->mp_num_free >= (MBUF_NUM_MBUFS / 2)) {
+    if (g_mbuf_pool.omp_pool->mp_num_free >= 5) {
         ble_get_packet(om);
     }
     return om;
 }
-#endif
 
+#if 0
 void
 bletest_execute(void)
 {
     int rc;
 
-#if (BLETEST_CFG_ROLE == BLETEST_ROLE_ADVERTISER)
     int i;
     uint16_t pktlen;
     uint16_t handle;
@@ -334,7 +401,8 @@ bletest_execute(void)
             connsm = ble_ll_conn_find_active_conn(handle);
             if (connsm) {
                 /* Set connection end time */
-                g_bletest_conn_end = os_time_get() + (OS_TICKS_PER_SEC * 17);
+                g_bletest_conn_end = os_time_get() + 
+                    (OS_TICKS_PER_SEC * (60 * 15));
                 g_bletest_state = 2;
             }
         } else if (g_bletest_state == 2) {
@@ -381,29 +449,87 @@ bletest_execute(void)
         }
         g_next_os_time += OS_TICKS_PER_SEC;
     }
-#endif
+}
+#else
+void
+bletest_execute(void)
+{
+    int i,j;
+    int rc;
+    uint16_t handle;
+    uint16_t pktlen;
+    struct os_mbuf *om;
 
-#if (BLETEST_CFG_ROLE == BLETEST_ROLE_SCANNER)
-    /* Enable scanning */
+    /* See if we should start advertising again */
+    if (g_bletest_current_conns < BLETEST_CFG_CONCURRENT_CONNS) {
+        handle = g_bletest_current_conns + 1;
+        if (ble_ll_conn_find_active_conn(handle)) {
+            /* advertising better be stopped! */
+            assert(ble_ll_adv_enabled() == 0);
+
+            /* Add to current connections */
+            ++g_bletest_current_conns;
+
+            /* Move to next connection */
+            if (g_bletest_current_conns < BLETEST_CFG_CONCURRENT_CONNS) {
+                /* restart initiating */
+                g_bletest_cur_peer_addr[5] += 1;
+                g_dev_addr[5] += 1;
+                bletest_init_advertising();
+                rc = host_hci_cmd_le_set_adv_enable(1);
+                host_hci_outstanding_opcode = 0;
+                assert(rc == 0);
+            }
+        }
+    }
+
+    /* See if it is time to hand a data packet to the connection */
     if ((int32_t)(os_time_get() - g_next_os_time) >= 0) {
-        if (g_bletest_state) {
-            rc = host_hci_cmd_le_set_scan_enable(0, BLETEST_CFG_FILT_DUP_ADV);
-            assert(rc == 0);
-            host_hci_outstanding_opcode = 0;
-            g_bletest_state = 0;
-        } else {
-            rc = host_hci_cmd_le_set_scan_enable(1, BLETEST_CFG_FILT_DUP_ADV);
-            assert(rc == 0);
-            host_hci_outstanding_opcode = 0;
-            g_bletest_state = 1;
+        if (g_bletest_current_conns) {
+            for (i = 0; i < g_bletest_current_conns; ++i) {
+                if ((g_last_handle_used == 0) || 
+                    (g_last_handle_used >= g_bletest_current_conns)) {
+                    g_last_handle_used = 1;
+                }
+                handle = g_last_handle_used;
+                if (ble_ll_conn_find_active_conn(handle)) {
+                    om = bletest_get_packet();
+                    if (om) {
+                        /* set payload length */
+                        pktlen = BLETEST_PKT_SIZE;
+                        om->om_len = BLETEST_PKT_SIZE + 4;
+
+                        /* Put the HCI header in the mbuf */
+                        htole16(om->om_data, handle);
+                        htole16(om->om_data + 2, om->om_len);
+
+                        /* Place L2CAP header in packet */
+                        htole16(om->om_data + 4, pktlen);
+                        om->om_data[6] = 0;
+                        om->om_data[7] = 0;
+
+                        /* Fill with incrementing pattern (starting from 1) */
+                        for (j = 0; j < pktlen; ++j) {
+                            om->om_data[8 + j] = (uint8_t)(j + 1);
+                        }
+
+                        /* Add length */
+                        om->om_len += 4;
+                        OS_MBUF_PKTHDR(om)->omp_len = om->om_len;
+                        ble_hci_transport_host_acl_data_send(om);
+
+                        /* Increment last handle used */
+                        ++g_last_handle_used;
+                    }
+                }
+            }
         }
-        g_next_os_time += (OS_TICKS_PER_SEC * 60);
+        g_next_os_time += OS_TICKS_PER_SEC;
     }
+}
 #endif
-#if (BLETEST_CFG_ROLE == BLETEST_ROLE_INITIATOR)
-    (void)rc;
+
 #endif
-}
 
 /**
  * Callback when BLE test timer expires. 
@@ -486,6 +612,13 @@ bletest_task_handler(void *arg)
     g_bletest_state = 0;
     g_next_os_time = os_time_get();
 
+    /* Begin advertising if we are an advertiser */
+#if (BLETEST_CFG_ROLE == BLETEST_ROLE_ADVERTISER)
+    rc = host_hci_cmd_le_set_adv_enable(1);
+    assert(rc == 0);
+    host_hci_outstanding_opcode = 0;
+#endif
+
     bletest_timer_cb(NULL);
 
     while (1) {
@@ -557,6 +690,7 @@ main(void)
 
     rc = os_mempool_init(&g_mbuf_mempool, MBUF_NUM_MBUFS, 
             MBUF_MEMBLOCK_SIZE, &g_mbuf_buffer[0], "mbuf_pool");
+    assert(rc == 0);
 
     rc = os_mbuf_pool_init(&g_mbuf_pool, &g_mbuf_mempool, MBUF_MEMBLOCK_SIZE, 
                            MBUF_NUM_MBUFS);
@@ -570,6 +704,13 @@ main(void)
     g_dev_addr[3] = 0x88;
     g_dev_addr[4] = 0x88;
     g_dev_addr[5] = 0x08;
+
+    g_bletest_cur_peer_addr[0] = 0x00;
+    g_bletest_cur_peer_addr[1] = 0x00;
+    g_bletest_cur_peer_addr[2] = 0x00;
+    g_bletest_cur_peer_addr[3] = 0x99;
+    g_bletest_cur_peer_addr[4] = 0x99;
+    g_bletest_cur_peer_addr[5] = 0x09;
 #else
     g_dev_addr[0] = 0x00;
     g_dev_addr[1] = 0x00;
@@ -577,6 +718,13 @@ main(void)
     g_dev_addr[3] = 0x99;
     g_dev_addr[4] = 0x99;
     g_dev_addr[5] = 0x09;
+
+    g_bletest_cur_peer_addr[0] = 0x00;
+    g_bletest_cur_peer_addr[1] = 0x00;
+    g_bletest_cur_peer_addr[2] = 0x00;
+    g_bletest_cur_peer_addr[3] = 0x88;
+    g_bletest_cur_peer_addr[4] = 0x88;
+    g_bletest_cur_peer_addr[5] = 0x08;
 #endif
 
     /* 


[2/2] incubator-mynewt-larva git commit: Many changes to the scheduler and link layer to allow for scheduling of multiple connections. Also allows concurrent connections and/or advertising and/or scanning and/or initiating state machines

Posted by we...@apache.org.
Many changes to the scheduler and link layer to allow for scheduling of multiple connections. Also allows concurrent connections and/or advertising and/or scanning and/or initiating state machines


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/b6e2b5ff
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/tree/b6e2b5ff
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/diff/b6e2b5ff

Branch: refs/heads/master
Commit: b6e2b5ffa358ad9696f71d30df4f94466f78ae67
Parents: ccc970c
Author: wes3 <wi...@micosa.io>
Authored: Mon Jan 18 16:14:37 2016 -0800
Committer: wes3 <wi...@micosa.io>
Committed: Mon Jan 18 16:14:50 2016 -0800

----------------------------------------------------------------------
 .../controller/include/controller/ble_ll.h      |  26 +-
 .../controller/include/controller/ble_ll_adv.h  |  13 +-
 .../controller/include/controller/ble_ll_conn.h |   8 +-
 .../controller/include/controller/ble_ll_hci.h  |   2 +-
 .../controller/include/controller/ble_ll_scan.h |  16 +-
 .../include/controller/ble_ll_sched.h           |  47 +-
 net/nimble/controller/src/ble_ll.c              | 125 +--
 net/nimble/controller/src/ble_ll_adv.c          | 264 ++++---
 net/nimble/controller/src/ble_ll_conn.c         | 682 +++++++++-------
 net/nimble/controller/src/ble_ll_conn_hci.c     |   4 +-
 net/nimble/controller/src/ble_ll_conn_priv.h    |  16 +-
 net/nimble/controller/src/ble_ll_ctrl.c         |   2 +-
 net/nimble/controller/src/ble_ll_scan.c         | 386 ++++++----
 net/nimble/controller/src/ble_ll_sched.c        | 770 ++++++++++++++++---
 net/nimble/drivers/native/src/ble_phy.c         |   9 +-
 net/nimble/drivers/nrf52/src/ble_phy.c          |  21 +-
 net/nimble/include/nimble/ble.h                 |  26 +-
 project/bletest/src/main.c                      | 232 +++++-
 18 files changed, 1885 insertions(+), 764 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/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 6e5b6e1..948d8e6 100644
--- a/net/nimble/controller/include/controller/ble_ll.h
+++ b/net/nimble/controller/include/controller/ble_ll.h
@@ -70,6 +70,8 @@ struct ble_ll_stats
     uint32_t hci_events_sent;
     uint32_t bad_ll_state;
     uint32_t bad_acl_hdr;
+    uint32_t sched_state_conn_errs;
+    uint32_t sched_state_adv_errs;
     uint32_t rx_bytes;
     uint32_t rx_valid_adv_pdus;
     uint32_t rx_invalid_adv_pdus;
@@ -108,7 +110,7 @@ extern struct ble_ll_stats g_ble_ll_stats;
 #define BLE_LL_EVENT_HCI_CMD        (OS_EVENT_T_PERUSER)
 #define BLE_LL_EVENT_ADV_EV_DONE    (OS_EVENT_T_PERUSER + 1)
 #define BLE_LL_EVENT_RX_PKT_IN      (OS_EVENT_T_PERUSER + 2)
-#define BLE_LL_EVENT_SCAN_WIN_END   (OS_EVENT_T_PERUSER + 3)
+#define BLE_LL_EVENT_SCAN           (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)
@@ -306,7 +308,8 @@ void ble_ll_acl_data_in(struct os_mbuf *txpkt);
 int ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan);
 
 /* Called by the PHY when a packet reception ends */
-int ble_ll_rx_end(struct os_mbuf *rxpdu, uint8_t chan, uint8_t crcok);
+struct ble_mbuf_hdr;
+int ble_ll_rx_end(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *ble_hdr);
 
 /*--- Controller API ---*/
 void ble_ll_mbuf_init(struct os_mbuf *m, uint8_t pdulen, uint8_t hdr);
@@ -336,10 +339,14 @@ uint8_t ble_ll_read_supp_features(void);
  * XXX: temporary LL debug log. Will get removed once we transition to real
  * log
  */ 
-#undef BLE_LL_LOG
-
-#define BLE_LL_LOG_ID_RX_START          (1)
-#define BLE_LL_LOG_ID_RX_END            (2)
+#define BLE_LL_LOG
+
+#define BLE_LL_LOG_ID_PHY_SETCHAN       (1)
+#define BLE_LL_LOG_ID_RX_START          (2)
+#define BLE_LL_LOG_ID_RX_END            (3)
+#define BLE_LL_LOG_ID_WFR_EXP           (4)
+#define BLE_LL_LOG_ID_PHY_TXEND         (5)
+#define BLE_LL_LOG_ID_PHY_DISABLE       (9)
 #define BLE_LL_LOG_ID_CONN_EV_START     (10)
 #define BLE_LL_LOG_ID_CONN_TX           (15)
 #define BLE_LL_LOG_ID_CONN_RX           (16)
@@ -347,11 +354,8 @@ uint8_t ble_ll_read_supp_features(void);
 #define BLE_LL_LOG_ID_CONN_RX_ACK       (18)
 #define BLE_LL_LOG_ID_CONN_EV_END       (20)
 #define BLE_LL_LOG_ID_CONN_END          (30)
-#define BLE_LL_LOG_ID_PHY_SETCHAN       (200)
-#define BLE_LL_LOG_ID_PHY_DISABLE       (201)
-#define BLE_LL_LOG_ID_PHY_ISR           (202)
-#define BLE_LL_LOG_ID_PHY_RX            (220)
-#define BLE_LL_LOG_ID_PHY_TX            (221)
+#define BLE_LL_LOG_ID_ADV_TXBEG         (50)
+#define BLE_LL_LOG_ID_ADV_TXDONE        (60)
 
 #ifdef BLE_LL_LOG
 void ble_ll_log(uint8_t id, uint8_t arg8, uint16_t arg16, uint32_t arg32);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/net/nimble/controller/include/controller/ble_ll_adv.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_adv.h b/net/nimble/controller/include/controller/ble_ll_adv.h
index a01df8c..b3bc298 100644
--- a/net/nimble/controller/include/controller/ble_ll_adv.h
+++ b/net/nimble/controller/include/controller/ble_ll_adv.h
@@ -129,10 +129,10 @@ void ble_ll_adv_init(void);
 void ble_ll_adv_reset(void);
 
 /* Called on rx pdu start when in advertising state */
-int ble_ll_adv_rx_pdu_start(uint8_t pdu_type, struct os_mbuf *rxpdu);
+int ble_ll_adv_rx_isr_start(uint8_t pdu_type, struct os_mbuf *rxpdu);
 
 /* Called on rx pdu end when in advertising state */
-int ble_ll_adv_rx_pdu_end(uint8_t pdu_type, struct os_mbuf *rxpdu);
+int ble_ll_adv_rx_isr_end(uint8_t pdu_type, struct os_mbuf *rxpdu, int crcok);
 
 /* Processes received packets at the link layer task */
 void ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf,
@@ -144,4 +144,13 @@ int ble_ll_adv_can_chg_whitelist(void);
 /* Called when a connection request has been received at the link layer */
 int ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr);
 
+/* Called when an advertising event has been scheduled */
+void ble_ll_adv_scheduled(uint32_t sch_start);
+
+/* Called to halt currently running advertising event */
+void ble_ll_adv_halt(void);
+
+/* Called to determine if advertising is enabled */
+uint8_t ble_ll_adv_enabled(void);
+
 #endif /* H_BLE_LL_ADV_ */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/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 a11e02d..444ee72 100644
--- a/net/nimble/controller/include/controller/ble_ll_conn.h
+++ b/net/nimble/controller/include/controller/ble_ll_conn.h
@@ -18,6 +18,8 @@
 #define H_BLE_LL_CONN_
 
 #include "os/os.h"
+#include "nimble/ble.h"
+#include "controller/ble_ll_sched.h"
 #include "hal/hal_cputime.h"
 
 /* Roles */
@@ -114,11 +116,12 @@ struct ble_ll_conn_sm
     uint32_t access_addr;
     uint32_t crcinit;           /* only low 24 bits used */
     uint32_t anchor_point;
-    uint32_t last_anchor_point;
+    uint32_t last_anchor_point; /* slave only */
     uint32_t ce_end_time;   /* cputime at which connection event should end */
     uint32_t terminate_timeout;
     uint32_t slave_cur_tx_win_usecs;
     uint32_t slave_cur_window_widening;
+    uint32_t last_scheduled;
 
     /* address information */
     uint8_t own_addr_type;
@@ -148,6 +151,9 @@ struct ble_ll_conn_sm
 
     /* LL control procedure response timer */
     struct os_callout_func ctrl_proc_rsp_timer;
+
+    /* For scheduling connections */
+    struct ble_ll_sched_item conn_sch;
 };
 
 /* 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/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 e9d98a2..32a093a 100644
--- a/net/nimble/controller/include/controller/ble_ll_hci.h
+++ b/net/nimble/controller/include/controller/ble_ll_hci.h
@@ -32,7 +32,7 @@
  * number of completed packets event to the host. This number is in
  * milliseconds.
  */
-#define BLE_LL_CFG_NUM_COMP_PKT_RATE    (1000)  /* msecs */
+#define BLE_LL_CFG_NUM_COMP_PKT_RATE    (2000)  /* msecs */
 
 /* Initialize LL HCI */
 void ble_ll_hci_init(void);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/net/nimble/controller/include/controller/ble_ll_scan.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_scan.h b/net/nimble/controller/include/controller/ble_ll_scan.h
index 31c57fe..75542c3 100644
--- a/net/nimble/controller/include/controller/ble_ll_scan.h
+++ b/net/nimble/controller/include/controller/ble_ll_scan.h
@@ -17,6 +17,8 @@
 #ifndef H_BLE_LL_SCAN_
 #define H_BLE_LL_SCAN_
 
+#include "controller/ble_ll_sched.h"
+
 /* 
  * Configuration items for the number of duplicate advertisers and the
  * number of advertisers from which we have heard a scan response 
@@ -77,9 +79,11 @@ struct ble_ll_scan_sm
     uint16_t backoff_count;
     uint16_t scan_itvl;
     uint16_t scan_window;
+    uint32_t last_sched_time;
     uint32_t scan_win_start_time;
     struct os_mbuf *scan_req_pdu;
-    struct os_event scan_win_end_ev;
+    struct os_event scan_sched_ev;
+    struct ble_ll_sched_item scan_sch;
 };
 
 /* Scan types */
@@ -96,7 +100,7 @@ int ble_ll_scan_set_enable(uint8_t *cmd);
 
 /*--- Controller Internal API ---*/
 /* Process scan window end event */
-void ble_ll_scan_win_end_proc(void *arg);
+void ble_ll_scan_event_proc(void *arg);
 
 /* Initialize the scanner */
 void ble_ll_scan_init(void);
@@ -105,10 +109,10 @@ void ble_ll_scan_init(void);
 void ble_ll_scan_reset(void);
 
 /* Called when Link Layer starts to receive a PDU and is in scanning state */
-int ble_ll_scan_rx_pdu_start(uint8_t pdu_type, struct os_mbuf *rxpdu);
+int ble_ll_scan_rx_isr_start(uint8_t pdu_type, struct os_mbuf *rxpdu);
 
 /* Called when Link Layer has finished receiving a PDU while scanning */
-int ble_ll_scan_rx_pdu_end(struct os_mbuf *rxpdu);
+int ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok);
 
 /* Process a scan response PDU */
 void ble_ll_scan_rx_pkt_in(uint8_t pdu_type, uint8_t *rxbuf, 
@@ -131,10 +135,10 @@ int ble_ll_scan_initiator_start(struct hci_create_conn *hcc);
 struct os_mbuf *ble_ll_scan_get_pdu(void);
 
 /* Stop the scanning state machine */
-void ble_ll_scan_sm_stop(struct ble_ll_scan_sm *scansm, int conn_created);
+void ble_ll_scan_sm_stop(int chk_disable);
 
 /* Resume scanning */
-void ble_ll_scan_resume(void);
+void ble_ll_scan_chk_resume(void);
 
 /* Called when wait for response timer expires in scanning mode */
 void ble_ll_scan_wfr_timer_exp(void);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/net/nimble/controller/include/controller/ble_ll_sched.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_sched.h b/net/nimble/controller/include/controller/ble_ll_sched.h
index 48914ae..eff9b2f 100644
--- a/net/nimble/controller/include/controller/ble_ll_sched.h
+++ b/net/nimble/controller/include/controller/ble_ll_sched.h
@@ -17,15 +17,16 @@
 #ifndef H_BLE_LL_SCHED_
 #define H_BLE_LL_SCHED_
 
+/* Time per BLE scheduler slot */
+#define BLE_LL_SCHED_USECS_PER_SLOT (1250)
+
 /* BLE scheduler errors */
 #define BLE_LL_SCHED_ERR_OVERLAP    (1)
 
 /* Types of scheduler events */
-#define BLE_LL_SCHED_TYPE_ADV       (0)
-#define BLE_LL_SCHED_TYPE_SCAN      (1)
-#define BLE_LL_SCHED_TYPE_TX        (2)
-#define BLE_LL_SCHED_TYPE_RX        (3)
-#define BLE_LL_SCHED_TYPE_CONN      (4)
+#define BLE_LL_SCHED_TYPE_ADV       (1)
+#define BLE_LL_SCHED_TYPE_SCAN      (2)
+#define BLE_LL_SCHED_TYPE_CONN      (3)
 
 /* Return values for schedule callback. */
 #define BLE_LL_SCHED_STATE_RUNNING  (0)
@@ -37,28 +38,48 @@ typedef int (*sched_cb_func)(struct ble_ll_sched_item *sch);
 
 struct ble_ll_sched_item
 {
-    int             sched_type;
+    uint8_t         sched_type;
+    uint8_t         enqueued;
     uint32_t        start_time;
     uint32_t        end_time;
-    uint32_t        next_wakeup;
     void            *cb_arg;
     sched_cb_func   sched_cb;
     TAILQ_ENTRY(ble_ll_sched_item) link;
 };
 
-/* Add an item to the schedule */
-int ble_ll_sched_add(struct ble_ll_sched_item *sch);
-
-/* Remove item(s) from schedule */
-int ble_ll_sched_rmv(uint8_t sched_type, void *cb_arg);
-
 /* Initialize the scheduler */
 int ble_ll_sched_init(void);
 
+/* Remove item(s) from schedule */
+void ble_ll_sched_rmv_elem(struct ble_ll_sched_item *sch);
+
 /* Get a schedule item */
 struct ble_ll_sched_item *ble_ll_sched_get_item(void);
 
 /* Free a schedule item */
 void ble_ll_sched_free_item(struct ble_ll_sched_item *sch);
 
+/* Schedule a new master connection */
+struct ble_ll_conn_sm;
+int ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, uint32_t adv_rxend, 
+                            uint8_t req_slots);
+
+/* Schedule a new slave connection */
+int ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm);
+
+/* Schedule a new advertising event */
+int ble_ll_sched_adv_new(struct ble_ll_sched_item *sch);
+
+/* Reschedule an advertising event */
+int ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch);
+
+/* Reschedule a connection that had previously been scheduled or that is over */
+int ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm * connsm);
+
+/* Schedule a scanning schedule item (start or stop) */
+void ble_ll_sched_scan(struct ble_ll_sched_item *sch);
+
+/* Stop the scheduler */
+void ble_ll_sched_stop(void);
+
 #endif /* H_LL_SCHED_ */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/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 927d82d..eb44261 100644
--- a/net/nimble/controller/src/ble_ll.c
+++ b/net/nimble/controller/src/ble_ll.c
@@ -29,15 +29,6 @@
 #include "ble_ll_conn_priv.h"
 #include "hal/hal_cputime.h"
 
-/* 
- * XXX: I need to re-think the whoele LL state code and how I deal with it.
- * I dont think I am handling it very well. The LL state should only change
- * at the LL task I think. I am also not sure how to make sure that any packets
- * handled by the LL are handled by the appropriate state. For example, can I
- * get a scan window end and then process packets? When the schedule event for
- * the scan window ends, what do I do to the LL state? Check all this out.
- */
-
 /* XXX:
  * 
  * 1) use the sanity task!
@@ -49,6 +40,11 @@
  * start of a frame. Need to look at the various states to see if this is the
  * right thing to do.
  * 
+ * 5) Make sure there is no way we can start a wfr timer and then have
+ * whatever event end and not stop the timer. We want to make sure the timer
+ * cant fire off unless we are sure that it will fire off when the device is
+ * in standby state. At least in standby we are sure no erroneous action will
+ * be taken
  */
 
 /* Configuration for supported features */
@@ -259,12 +255,17 @@ ble_ll_is_our_devaddr(uint8_t *addr, int addr_type)
 void
 ble_ll_wfr_timer_exp(void *arg)
 {
-    struct ble_ll_obj *lldata;
+    int rx_start;
+    uint8_t lls;
+
+    rx_start = ble_phy_rx_started();
+    lls = g_ble_ll_data.ll_state;
+
+    ble_ll_log(BLE_LL_LOG_ID_WFR_EXP, lls, 0, (uint32_t)rx_start);
 
     /* If we have started a reception, there is nothing to do here */
-    if (!ble_phy_rx_started()) {
-        lldata = &g_ble_ll_data;
-        switch (lldata->ll_state) {
+    if (!rx_start) {
+        switch (lls) {
         case BLE_LL_STATE_ADV:
             ble_ll_adv_wfr_timer_exp();
             break;
@@ -365,6 +366,7 @@ ble_ll_rx_pkt_in(void)
     os_sr_t sr;
     uint8_t pdu_type;
     uint8_t *rxbuf;
+    uint8_t crcok;
     struct os_mbuf_pkthdr *pkthdr;
     struct ble_mbuf_hdr *ble_hdr;
     struct os_mbuf *m;
@@ -383,17 +385,18 @@ ble_ll_rx_pkt_in(void)
         /* Count statistics */
         rxbuf = m->om_data;
         ble_hdr = BLE_MBUF_HDR_PTR(m); 
-        if (ble_hdr->rxinfo.crcok) {
+        crcok = BLE_MBUF_HDR_CRC_OK(ble_hdr);
+        if (crcok) {
             /* The total bytes count the PDU header and PDU payload */
             g_ble_ll_stats.rx_bytes += pkthdr->omp_len;
         }
 
         if (ble_hdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) {
-            ble_ll_conn_rx_data_pdu(m, ble_hdr->rxinfo.crcok);
+            ble_ll_conn_rx_data_pdu(m, ble_hdr);
         } else {
             /* Get advertising PDU type */
             pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK;
-            if (ble_hdr->rxinfo.crcok) {
+            if (crcok) {
                 /* Count by type only with valid crc */
                 ++g_ble_ll_stats.rx_valid_adv_pdus;
                 ble_ll_count_rx_adv_pdus(pdu_type);
@@ -402,7 +405,7 @@ ble_ll_rx_pkt_in(void)
             }
 
             /* Process the PDU */
-            switch (g_ble_ll_data.ll_state) {
+            switch (BLE_MBUF_HDR_RX_STATE(ble_hdr)) {
             case BLE_LL_STATE_ADV:
                 ble_ll_adv_rx_pkt_in(pdu_type, rxbuf, ble_hdr);
                 break;
@@ -418,6 +421,7 @@ ble_ll_rx_pkt_in(void)
                 break;
             }
 
+
             /* Free the packet buffer */
             os_mbuf_free(m);
         }
@@ -488,7 +492,7 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan)
          */
         if (g_ble_ll_data.ll_state == BLE_LL_STATE_CONNECTION) {
             /* Call conection pdu rx start function */
-            ble_ll_conn_rx_pdu_start();
+            ble_ll_conn_rx_isr_start();
 
             /* Set up to go from rx to tx */
             rc = 1;
@@ -504,7 +508,7 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan)
 
     switch (g_ble_ll_data.ll_state) {
     case BLE_LL_STATE_ADV:
-        rc = ble_ll_adv_rx_pdu_start(pdu_type, rxpdu);
+        rc = ble_ll_adv_rx_isr_start(pdu_type, rxpdu);
         break;
     case BLE_LL_STATE_INITIATING:
         if ((pdu_type == BLE_ADV_PDU_TYPE_ADV_IND) ||
@@ -515,7 +519,7 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan)
         }
         break;
     case BLE_LL_STATE_SCANNING:
-        rc = ble_ll_scan_rx_pdu_start(pdu_type, rxpdu);
+        rc = ble_ll_scan_rx_isr_start(pdu_type, rxpdu);
         break;
     case BLE_LL_STATE_CONNECTION:
         /* Should not occur */
@@ -537,7 +541,8 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan)
  *  
  * NOTE: Called from interrupt context!
  * 
- * @param rxbuf 
+ * @param rxpdu Pointer to received PDU 
+ *        ble_hdr Pointer to BLE header of received mbuf 
  * 
  * @return int 
  *       < 0: Disable the phy after reception.
@@ -545,18 +550,24 @@ ble_ll_rx_start(struct os_mbuf *rxpdu, uint8_t chan)
  *       > 0: Do not disable PHY as that has already been done.
  */
 int
-ble_ll_rx_end(struct os_mbuf *rxpdu, uint8_t chan, uint8_t crcok)
+ble_ll_rx_end(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *ble_hdr)
 {
     int rc;
     int badpkt;
     uint8_t pdu_type;
     uint8_t len;
+    uint8_t chan;
+    uint8_t crcok;
     uint16_t mblen;
     uint8_t *rxbuf;
 
     /* Set the rx buffer pointer to the start of the received data */
     rxbuf = rxpdu->om_data;
 
+    /* Get channel and CRC status from BLE header */
+    chan = ble_hdr->rxinfo.channel;
+    crcok = BLE_MBUF_HDR_CRC_OK(ble_hdr);
+
     ble_ll_log(BLE_LL_LOG_ID_RX_END, 
                chan, 
                ((uint16_t)crcok << 8) | rxbuf[1], 
@@ -581,14 +592,19 @@ ble_ll_rx_end(struct os_mbuf *rxpdu, uint8_t chan, uint8_t crcok)
          * Data channel pdu. We should be in CONNECTION state with an
          * ongoing connection.
          */
-        rc = ble_ll_conn_rx_pdu_end(rxpdu, ble_phy_access_addr_get());
+        rc = ble_ll_conn_rx_isr_end(rxpdu, ble_phy_access_addr_get());
         return rc;
     } 
 
-    /* Get advertising PDU type */
+    /* Get advertising PDU type and length */
     pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK;
     len = rxbuf[1] & BLE_ADV_PDU_HDR_LEN_MASK;
 
+    /* Setup the mbuf lengths */
+    mblen = len + BLE_LL_PDU_HDR_LEN;
+    OS_MBUF_PKTHDR(rxpdu)->omp_len = mblen;
+    rxpdu->om_len = mblen;
+
     /* If the CRC checks, make sure lengths check! */
     if (crcok) {
         badpkt = 0;
@@ -621,38 +637,35 @@ ble_ll_rx_end(struct os_mbuf *rxpdu, uint8_t chan, uint8_t crcok)
         if (badpkt) {
             ++g_ble_ll_stats.rx_adv_malformed_pkts;
             os_mbuf_free(rxpdu);
-            return -1;
+            rxpdu = NULL;
+            rc = -1;
         }
     }
 
-    /* Setup the mbuf lengths */
-    mblen = len + BLE_LL_PDU_HDR_LEN;
-    OS_MBUF_PKTHDR(rxpdu)->omp_len = mblen;
-    rxpdu->om_len = mblen;
 
     /* Hand packet to the appropriate state machine (if crc ok) */
-    rc = -1;
-    if (crcok) {
-        switch (g_ble_ll_data.ll_state) {
-        case BLE_LL_STATE_ADV:
-            rc = ble_ll_adv_rx_pdu_end(pdu_type, rxpdu);
-            break;
-        case BLE_LL_STATE_SCANNING:
-            rc = ble_ll_scan_rx_pdu_end(rxpdu);
-            break;
-        case BLE_LL_STATE_INITIATING:
-            rc = ble_ll_init_rx_pdu_end(rxpdu);
-            break;
-        /* Invalid states */
-        case BLE_LL_STATE_CONNECTION:
-        default:
-            assert(0);
-            break;
-        }
+    switch (BLE_MBUF_HDR_RX_STATE(ble_hdr)) {
+    case BLE_LL_STATE_ADV:
+        rc = ble_ll_adv_rx_isr_end(pdu_type, rxpdu, crcok);
+        break;
+    case BLE_LL_STATE_SCANNING:
+        rc = ble_ll_scan_rx_isr_end(rxpdu, crcok);
+        break;
+    case BLE_LL_STATE_INITIATING:
+        rc = ble_ll_init_rx_isr_end(rxpdu, crcok);
+        break;
+    /* Invalid states */
+    case BLE_LL_STATE_CONNECTION:
+    default:
+        rc = -1;
+        assert(0);
+        break;
     }
 
     /* Hand packet up to higher layer (regardless of CRC failure) */
-    ble_ll_rx_pdu_in(rxpdu);
+    if (rxpdu) {
+        ble_ll_rx_pdu_in(rxpdu);
+    }
 
     return rc;
 }
@@ -668,6 +681,7 @@ void
 ble_ll_task(void *arg)
 {
     struct os_event *ev;
+    struct os_callout_func *cf;
 
     /* Init ble phy */
     ble_phy_init();
@@ -681,9 +695,11 @@ ble_ll_task(void *arg)
     /* Wait for an event */
     while (1) {
         ev = os_eventq_get(&g_ble_ll_data.ll_evq);
-
         switch (ev->ev_type) {
         case OS_EVENT_T_TIMER:
+            cf = (struct os_callout_func *)ev;
+            assert(cf->cf_func);
+            cf->cf_func(cf->cf_arg);
             break;
         case BLE_LL_EVENT_HCI_CMD:
             /* Process HCI command */
@@ -692,8 +708,8 @@ ble_ll_task(void *arg)
         case BLE_LL_EVENT_ADV_EV_DONE:
             ble_ll_adv_event_done(ev->ev_arg);
             break;
-        case BLE_LL_EVENT_SCAN_WIN_END:
-            ble_ll_scan_win_end_proc(ev->ev_arg);
+        case BLE_LL_EVENT_SCAN:
+            ble_ll_scan_event_proc(ev->ev_arg);
             break;
         case BLE_LL_EVENT_RX_PKT_IN:
             ble_ll_rx_pkt_in();
@@ -821,7 +837,8 @@ ble_ll_mbuf_init(struct os_mbuf *m, uint8_t pdulen, uint8_t hdr)
  * layer; it does not perform a HW reset of the controller nor does it reset 
  * the HCI interface. 
  * 
- * 
+ * Context: Link Layer task (HCI command) 
+ *  
  * @return int The ble error code to place in the command complete event that 
  * is returned when this command is issued. 
  */
@@ -829,12 +846,16 @@ int
 ble_ll_reset(void)
 {
     int rc;
+    os_sr_t sr;
 
     /* Stop the phy */
     ble_phy_disable();
 
     /* Stop any wait for response timer */
+    OS_ENTER_CRITICAL(sr);
     ble_ll_wfr_disable();
+    ble_ll_sched_stop();
+    OS_EXIT_CRITICAL(sr);
 
     /* Stop any scanning */
     ble_ll_scan_reset();

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/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 5302f66..d74b61a 100644
--- a/net/nimble/controller/src/ble_ll_adv.c
+++ b/net/nimble/controller/src/ble_ll_adv.c
@@ -46,14 +46,12 @@
  * 2) Only public device addresses supported right now.
  * 3) How do features get supported? What happens if device does not support
  * advertising? (for example)
- * 4) Correct calculation of schedule start and end times for the various
- * scheduled advertising activities.
- * 5) How to determine the advertising interval we will actually use. As of
+ * 4) How to determine the advertising interval we will actually use. As of
  * now, we set it to max.
- * 6) Currently, when we set scheduling events, we dont take into account
- * processor overhead/delays. We will want to do that.
- * 7) How does the advertising channel tx power get set? I dont implement
+ * 5) How does the advertising channel tx power get set? I dont implement
  * that currently.
+ * 6) The time between transmissions inside an advertising event is set to
+ * max. Need to deal with this.
  */
 
 /* 
@@ -89,6 +87,7 @@ struct ble_ll_adv_sm
     struct os_mbuf *adv_pdu;
     struct os_mbuf *scan_rsp_pdu;
     struct os_event adv_txdone_ev;
+    struct ble_ll_sched_item adv_sch;
 };
 
 /* The advertising state machine global object */
@@ -149,7 +148,6 @@ ble_ll_adv_first_chan(struct ble_ll_adv_sm *advsm)
     return adv_chan;
 }
 
-
 /**
  * Compares the advertiser address in an advertising PDU (scan request or 
  * connect request) with our address to see if there is a match
@@ -327,15 +325,24 @@ ble_ll_adv_scan_rsp_pdu_make(struct ble_ll_adv_sm *advsm)
 }
 
 /**
- * Scheduler callback when an advertising PDU has been sent. 
+ * Called to indicate the advertising event is over.
+ *  
+ * Context: Interrupt 
+ * 
+ * @param advsm 
  * 
- * @param arg 
  */
-static int
-ble_ll_adv_tx_done_cb(struct ble_ll_sched_item *sch)
+static void
+ble_ll_adv_tx_done(void *arg)
 {
-    os_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_adv_sm.adv_txdone_ev);
-    return BLE_LL_SCHED_STATE_DONE;
+    struct ble_ll_adv_sm *advsm;
+
+    advsm = (struct ble_ll_adv_sm *)arg;
+    os_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
+
+    ble_ll_log(BLE_LL_LOG_ID_ADV_TXDONE, ble_ll_state_get(), 0, 0);
+
+    ble_ll_state_set(BLE_LL_STATE_STANDBY);
 }
 
 /**
@@ -363,24 +370,25 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch)
     rc = ble_phy_setchan(advsm->adv_chan, 0, 0);
     assert(rc == 0);
 
-    /* Set the callbacks */
-    ble_phy_set_txend_cb(NULL, NULL);
-
     /* Set phy mode based on type of advertisement */
     if (advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) {
         end_trans = BLE_PHY_TRANSITION_NONE;
+        ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm);
     } else {
         end_trans = BLE_PHY_TRANSITION_TX_RX;
+        ble_phy_set_txend_cb(NULL, NULL);
     }
 
     /* This is for debug */
     start_time = cputime_get32();
 
+    /* XXX: transmit using an output compare */
     /* Transmit advertisement */
     rc = ble_phy_tx(advsm->adv_pdu, BLE_PHY_TRANSITION_NONE, end_trans);
     if (rc) {
         /* Transmit failed. */
-        rc = ble_ll_adv_tx_done_cb(sch);
+        ble_ll_adv_tx_done(advsm);
+        rc =  BLE_LL_SCHED_STATE_DONE;
     } else {
         /* Check if we were late getting here */
         if ((int32_t)(start_time - (advsm->adv_pdu_start_time -
@@ -394,68 +402,71 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch)
         /* Count # of adv. sent */
         ++g_ble_ll_adv_stats.adv_txg;
 
-        /* Set next schedule wakeup time */
-        sch->next_wakeup = sch->end_time;
-        sch->sched_cb = ble_ll_adv_tx_done_cb;
-
+        /* This schedule item is now running */
         rc = BLE_LL_SCHED_STATE_RUNNING;
     }
 
     return rc;
 }
 
-static struct ble_ll_sched_item *
-ble_ll_adv_sched_set(struct ble_ll_adv_sm *advsm)
+static void
+ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm, int sched_new)
 {
-    int rc;
     uint32_t max_usecs;
     struct ble_ll_sched_item *sch;
 
-    sch = ble_ll_sched_get_item();
-    if (sch) {
-        /* Set sched type */
-        sch->sched_type = BLE_LL_SCHED_TYPE_ADV;
+    sch = &advsm->adv_sch;
+    sch->cb_arg = advsm;
+    sch->sched_cb = ble_ll_adv_tx_start_cb;
+    sch->sched_type = BLE_LL_SCHED_TYPE_ADV;
 
-        /* XXX: HW output compare to trigger tx start? Look into this */
-        /* Set the start time of the event */
-        sch->start_time = advsm->adv_pdu_start_time - 
-            cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+    /* Set end time to maximum time this schedule item may take */
+    max_usecs = BLE_TX_DUR_USECS_M(advsm->adv_pdu_len);
+    switch (advsm->adv_type) {
+    case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD:
+    case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD:
+        max_usecs += BLE_LL_ADV_DIRECT_SCHED_MAX_USECS;
+        break;
+    case BLE_HCI_ADV_TYPE_ADV_IND:
+    case BLE_HCI_ADV_TYPE_ADV_SCAN_IND:
+        max_usecs += BLE_LL_ADV_SCHED_MAX_USECS;
+        break;
+    default:
+        break;
+    }
 
-        /* Set the callback and argument */
-        sch->cb_arg = advsm;
-        sch->sched_cb = ble_ll_adv_tx_start_cb;
-
-        /* Set end time to maximum time this schedule item may take */
-        max_usecs = BLE_TX_DUR_USECS_M(advsm->adv_pdu_len);
-        switch (advsm->adv_type) {
-        case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD:
-        case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD:
-            max_usecs += BLE_LL_ADV_DIRECT_SCHED_MAX_USECS;
-            break;
-        case BLE_HCI_ADV_TYPE_ADV_IND:
-        case BLE_HCI_ADV_TYPE_ADV_SCAN_IND:
-            max_usecs += BLE_LL_ADV_SCHED_MAX_USECS;
-            break;
-        default:
-            break;
-        }
+    /* 
+     * XXX: For now, just schedule some additional time so we insure we have
+     * enough time to do everything we want.
+     */
+    max_usecs += XCVR_PROC_DELAY_USECS;
 
+    if (sched_new) {
         /* 
-         * We dont really care if this is super accurate; it really is only
-         * used to block time in the scheduler.
-         */ 
-        sch->end_time = advsm->adv_pdu_start_time +
-            cputime_usecs_to_ticks(max_usecs);
-
-        /* XXX: for now, we cant get an overlap so assert on error. */
-        /* Add the item to the scheduler */
-        rc = ble_ll_sched_add(sch);
-        assert(rc == 0);
+         * We have to add the scheduling delay and tx start delay to the max
+         * time of the event since the pdu does not start at the scheduled start.
+         */
+        max_usecs += XCVR_TX_SCHED_DELAY_USECS;
+        sch->start_time = cputime_get32();
+        sch->end_time = sch->start_time + cputime_usecs_to_ticks(max_usecs);
     } else {
-        ++g_ble_ll_adv_stats.cant_set_sched;
+        sch->start_time = advsm->adv_pdu_start_time - 
+            cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+        sch->end_time = advsm->adv_pdu_start_time + 
+            cputime_usecs_to_ticks(max_usecs);
     }
+}
 
-    return sch;
+/**
+ * Called when advertising need to be halted. This normally should not be called 
+ * and is only called when a scheduled item executes but advertising is still 
+ * running. 
+ * 
+ */
+void
+ble_ll_adv_halt(void)
+{
+    ble_ll_adv_tx_done(&g_ble_ll_adv_sm);
 }
 
 /**
@@ -575,19 +586,23 @@ ble_ll_adv_set_adv_params(uint8_t *cmd)
 static void
 ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm)
 {
+    os_sr_t sr;
+
     if (advsm->enabled) {
         /* Disable whitelisting (just in case) */
         ble_ll_whitelist_disable();
 
         /* Remove any scheduled advertising items */
-        ble_ll_sched_rmv(BLE_LL_SCHED_TYPE_ADV, NULL);
+        ble_ll_sched_rmv_elem(&advsm->adv_sch);
         os_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
 
         /* Set to standby if we are no longer advertising */
+        OS_ENTER_CRITICAL(sr);
         if (ble_ll_state_get() == BLE_LL_STATE_ADV) {
             ble_ll_wfr_disable();
             ble_ll_state_set(BLE_LL_STATE_STANDBY);
         }
+        OS_EXIT_CRITICAL(sr);
 
         /* Disable advertising */
         advsm->enabled = 0;
@@ -608,9 +623,7 @@ ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm)
 static int
 ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
 {
-    int rc;
     uint8_t adv_chan;
-    struct ble_ll_sched_item *sch;
 
     /* 
      * XXX: not sure if I should do this or just report whatever random
@@ -661,12 +674,25 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
     }
 
     /* 
-     * Set start time for the advertising event. This time is the same
-     * as the time we will send the first PDU. Since there does not seem
-     * to be any requirements as to when we start, we do it asap.
-     */ 
-    advsm->adv_event_start_time = cputime_get32() +
-        cputime_usecs_to_ticks(BLE_LL_IFS + XCVR_PROC_DELAY_USECS);
+     * Schedule advertising. We set the initial schedule start and end
+     * times to the earliest possible start/end.
+     */
+    ble_ll_adv_set_sched(advsm, 1);
+    ble_ll_sched_adv_new(&advsm->adv_sch);
+
+    return BLE_ERR_SUCCESS;
+}
+
+void
+ble_ll_adv_scheduled(uint32_t sch_start)
+{
+    struct ble_ll_adv_sm *advsm;
+
+    advsm = &g_ble_ll_adv_sm;
+
+    /* The event start time is when we start transmission of the adv PDU */
+    advsm->adv_event_start_time = sch_start +
+        cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
 
     advsm->adv_pdu_start_time = advsm->adv_event_start_time;
 
@@ -677,17 +703,6 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
      */
     advsm->adv_dir_hd_end_time = advsm->adv_event_start_time +
         cputime_usecs_to_ticks(BLE_LL_ADV_STATE_HD_MAX * 1000);
-
-    /* Add to schedule. If we cant, we will just inform host we are too busy */
-    rc = BLE_ERR_SUCCESS;
-    sch = ble_ll_adv_sched_set(advsm);
-    if (!sch) {
-        advsm->enabled = 0;
-        ble_ll_whitelist_disable();
-        rc = BLE_ERR_CTLR_BUSY;
-    }
-
-    return rc;
 }
 
 /**
@@ -707,7 +722,9 @@ ble_ll_adv_read_txpwr(uint8_t *rspbuf, uint8_t *rsplen)
 }
 
 /**
- * Turn advertising on/off.
+ * Turn advertising on/off. 
+ *  
+ * Context: Link Layer task 
  * 
  * @param cmd 
  * 
@@ -873,7 +890,7 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu)
     /* Setup to transmit the scan response if appropriate */
     rc = -1;
     if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) {
-        /* NOTE: no callback nneds to be set as it should be NULL already */
+        ble_phy_set_txend_cb(ble_ll_adv_tx_done, &g_ble_ll_adv_sm);
         rc = ble_phy_tx(advsm->scan_rsp_pdu, BLE_PHY_TRANSITION_RX_TX, 
                         BLE_PHY_TRANSITION_NONE);
         if (!rc) {
@@ -964,15 +981,25 @@ ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr)
  *       > 0: Do not disable PHY as that has already been done.
  */
 int
-ble_ll_adv_rx_pdu_end(uint8_t pdu_type, struct os_mbuf *rxpdu)
+ble_ll_adv_rx_isr_end(uint8_t pdu_type, struct os_mbuf *rxpdu, int crcok)
 {
     int rc;
 
     rc = -1;
-    if ((pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) ||
-        (pdu_type == BLE_ADV_PDU_TYPE_CONNECT_REQ)) {
-        /* Process request */
-        rc = ble_ll_adv_rx_req(pdu_type, rxpdu);
+    if (rxpdu == NULL) {
+        ble_ll_adv_tx_done(&g_ble_ll_adv_sm);
+    } else {
+        if (crcok) {
+            if ((pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) ||
+                (pdu_type == BLE_ADV_PDU_TYPE_CONNECT_REQ)) {
+                /* Process request */
+                rc = ble_ll_adv_rx_req(pdu_type, rxpdu);
+            }
+        }
+    }
+
+    if (rc) {
+        ble_ll_state_set(BLE_LL_STATE_STANDBY);
     }
 
     return rc;
@@ -997,12 +1024,20 @@ ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf, struct ble_mbuf_hdr *hdr)
     int adv_event_over;
 
     /* 
-     * We should remove the schedule item in all cases except when we
-     * are sending a scan response or we have stopped advertising due to
-     * receiving a connect request
+     * If we have received a scan request and we are transmitting a response
+     * or we have received a valid connect request, dont "end" the advertising
+     * event. In the case of a connect request we will stop advertising. In
+     * the case of the scan response transmission we will get a transmit
+     * end callback.
+     * 
+     * XXX: I dont know why I wait to reschedule after transmitting a scan
+     * response. I wont schedule over it and I can use the transmission time
+     * to schedule the next advertising event. I also get rid of the code to
+     * deal with the "scan response transmitted". All depends on how we
+     * schedule the next transmissions in the advertising event.
      */
     adv_event_over = 1;
-    if (hdr->rxinfo.crcok) {
+    if (BLE_MBUF_HDR_CRC_OK(hdr)) {
         if (ptype == BLE_ADV_PDU_TYPE_CONNECT_REQ) {
             if (ble_ll_adv_conn_req_rxd(rxbuf, hdr)) {
                 adv_event_over = 0;
@@ -1034,7 +1069,7 @@ ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf, struct ble_mbuf_hdr *hdr)
  *   > 0: Continue to receive frame and go from rx to tx when done
  */
 int
-ble_ll_adv_rx_pdu_start(uint8_t pdu_type, struct os_mbuf *rxpdu)
+ble_ll_adv_rx_isr_start(uint8_t pdu_type, struct os_mbuf *rxpdu)
 {
     int rc;
     struct ble_ll_adv_sm *advsm;
@@ -1061,6 +1096,14 @@ ble_ll_adv_rx_pdu_start(uint8_t pdu_type, struct os_mbuf *rxpdu)
         }
     }
 
+    /* 
+     * If we abort the frame, we need to post the LL task to check if the
+     * advertising event is over.
+     */
+    if (rc < 0) {
+        ble_ll_adv_tx_done(advsm);
+    }
+
     return rc;
 }
 
@@ -1078,15 +1121,19 @@ ble_ll_adv_event_done(void *arg)
     uint8_t final_adv_chan;
     int32_t delta_t;
     uint32_t itvl;
+    uint32_t start_time;
     struct ble_ll_adv_sm *advsm;
 
     /* Stop advertising event */
     advsm = (struct ble_ll_adv_sm *)arg;
     assert(advsm->enabled);
 
-    ble_ll_sched_rmv(BLE_LL_SCHED_TYPE_ADV, NULL);
+    /* Check if we need to resume scanning */
+    ble_ll_scan_chk_resume();
+
+    /* Remove the element from the schedule if it is still there. */
+    ble_ll_sched_rmv_elem(&advsm->adv_sch);
     os_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
-    ble_ll_state_set(BLE_LL_STATE_STANDBY);
 
     /* For debug purposes */
 #ifdef BLETEST
@@ -1144,7 +1191,10 @@ ble_ll_adv_event_done(void *arg)
      * count a statistic and close the current advertising event. We will
      * then setup the next advertising event.
      */
-    delta_t = (int32_t)(advsm->adv_pdu_start_time - cputime_get32());
+    start_time = advsm->adv_pdu_start_time - 
+        cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
+
+    delta_t = (int32_t)(start_time - cputime_get32());
     if (delta_t < 0) {
         /* Count times we were late */
         ++g_ble_ll_adv_stats.late_tx_done;
@@ -1179,9 +1229,14 @@ ble_ll_adv_event_done(void *arg)
         }
     }
 
-    if (!ble_ll_adv_sched_set(advsm)) {
-        /* XXX: we will need to set a timer here to wake us up */
-        assert(0);
+    ble_ll_adv_set_sched(advsm, 0);
+
+    /* 
+     * In the unlikely event we cant reschedule this, just post a done
+     * event and we will reschedule the next advertising event
+     */ 
+    if (ble_ll_sched_adv_reschedule(&advsm->adv_sch)) {
+        os_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev);
     }
 }
 
@@ -1217,7 +1272,7 @@ void
 ble_ll_adv_wfr_timer_exp(void)
 {
     ble_phy_disable();
-    os_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_adv_sm.adv_txdone_ev);
+    ble_ll_adv_tx_done(&g_ble_ll_adv_sm);
 }
 
 /**
@@ -1246,6 +1301,13 @@ ble_ll_adv_reset(void)
     ble_ll_adv_init();
 }
 
+/* Called to determine if advertising is enabled */
+uint8_t
+ble_ll_adv_enabled(void)
+{
+    return g_ble_ll_adv_sm.enabled;
+}
+
 /**
  * Initialize the advertising functionality of a BLE device. This should 
  * be called once on initialization

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/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 4566d10..373909b 100644
--- a/net/nimble/controller/src/ble_ll_conn.c
+++ b/net/nimble/controller/src/ble_ll_conn.c
@@ -32,6 +32,13 @@
 #include "hal/hal_cputime.h"
 #include "hal/hal_gpio.h"
 
+/* 
+ * XXX: looks like the current code will allow the 1st packet in a
+ * connection to extend past the end of the allocated connection end
+ * time. That is not good. Need to deal with that. Need to extend connection
+ * end time.
+ */
+
 /* XXX TODO
  * 1) Add set channel map command and implement channel change procedure.
  * 2) Make sure we have implemented all ways a connection can die/end. Not
@@ -56,8 +63,22 @@
  * the host that issued the create connection.
  * 9) How does peer address get set if we are using whitelist? Look at filter
  * policy and make sure you are doing this correctly.
+ * 10) Right now I use a fixed definition for required slots. CHange this.
+ * 11) Use output compare for transmit.
+ */
+
+/* 
+ * XXX: How should we deal with a late connection event? We need to determine
+ * what we want to do under the following cases:
+ *  1) The current connection event has not ended but a schedule item starts
+ *  2) The connection event start cb is called but we are later than we
+ *  expected. What to do? If we cant transmit at correct point in slot we
+ *  are hosed. Well, anchor point can get really messed up!
  */
 
+/* XXX: we need to make sure we hit the proper tx time for the anchor or we
+   could mess up the slave. Use output compare */
+
 /* XXX: this does not belong here! Move to transport? */
 extern int ble_hs_rx_data(struct os_mbuf *om);
 
@@ -76,19 +97,25 @@ extern int ble_hs_rx_data(struct os_mbuf *om);
  * XXX: move this definition and figure out how we determine the worst-case
  * jitter (spec. should have this).
  */
-#define BLE_LL_WFR_USECS    (BLE_LL_IFS + 40 + 32)
+#define BLE_LL_WFR_USECS                    (BLE_LL_IFS + 40 + 32)
 
 /* Configuration parameters */
-#define BLE_LL_CONN_CFG_TX_WIN_SIZE         (1)
-#define BLE_LL_CONN_CFG_TX_WIN_OFF          (0)
-#define BLE_LL_CONN_CFG_MASTER_SCA          (BLE_MASTER_SCA_251_500_PPM << 5)
-#define BLE_LL_CONN_CFG_MAX_CONNS           (8)
-#define BLE_LL_CONN_CFG_OUR_SCA             (500)   /* in ppm */
+#define BLE_LL_CFG_CONN_TX_WIN_SIZE         (1)
+#define BLE_LL_CFG_CONN_TX_WIN_OFF          (0)
+#define BLE_LL_CFG_CONN_MASTER_SCA          (BLE_MASTER_SCA_251_500_PPM << 5)
+#define BLE_LL_CFG_CONN_MAX_CONNS           (8)
+#define BLE_LL_CFG_CONN_OUR_SCA             (60)    /* in ppm */
+#define BLE_LL_CFG_CONN_INIT_SLOTS          (8)
+
+/* We cannot have more than 254 connections given our current implementation */
+#if (BLE_LL_CFG_CONN_MAX_CONNS >= 255)
+    #error "Maximum # of connections is 254"
+#endif
 
 /* LL configuration definitions */
 #define BLE_LL_CFG_SUPP_MAX_RX_BYTES        (251)
-#define BLE_LL_CFG_SUPP_MAX_TX_BYTES        (251)
-#define BLE_LL_CFG_CONN_INIT_MAX_TX_BYTES   (251)
+#define BLE_LL_CFG_SUPP_MAX_TX_BYTES        (27)
+#define BLE_LL_CFG_CONN_INIT_MAX_TX_BYTES   (27)
 
 /* Sleep clock accuracy table (in ppm) */
 static const uint16_t g_ble_sca_ppm_tbl[8] =
@@ -115,7 +142,7 @@ struct ble_ll_conn_sm *g_ble_ll_conn_create_sm;
 struct ble_ll_conn_sm *g_ble_ll_conn_cur_sm;
 
 /* Connection state machine array */
-struct ble_ll_conn_sm g_ble_ll_conn_sm[BLE_LL_CONN_CFG_MAX_CONNS];
+struct ble_ll_conn_sm g_ble_ll_conn_sm[BLE_LL_CFG_CONN_MAX_CONNS];
 
 /* List of active connections */
 struct ble_ll_conn_active_list g_ble_ll_conn_active_list;
@@ -149,6 +176,40 @@ struct ble_ll_conn_stats g_ble_ll_conn_stats;
 /* Some helpful macros */
 #define BLE_IS_RETRY_M(ble_hdr) ((ble_hdr)->txinfo.flags & BLE_MBUF_HDR_F_TXD)
 
+int 
+ble_ll_conn_is_lru(struct ble_ll_conn_sm *s1, struct ble_ll_conn_sm *s2)
+{
+    int rc;
+
+    /* Set time that we last serviced the schedule */
+    if ((int32_t)(s1->last_scheduled - s2->last_scheduled) < 0) {
+        rc = 1;
+    } else {
+        rc = 0;
+    }
+
+    return rc;
+}
+
+/**
+ * Called to return the currently running connection state machine end time. 
+ * Always called when interrupts are disabled.
+ * 
+ * @return uint32_t 
+ */
+uint32_t
+ble_ll_conn_get_ce_end_time(void)
+{
+    uint32_t ce_end_time;
+
+    if (g_ble_ll_conn_cur_sm) {
+        ce_end_time = g_ble_ll_conn_cur_sm->ce_end_time;
+    } else {
+        ce_end_time = cputime_get32();
+    }
+    return ce_end_time;
+}
+
 /**
  * Checks if pdu is a L2CAP pdu, meaning it is not a control pdu nor an empty 
  * pdu. Called only for transmit PDU's.
@@ -192,9 +253,6 @@ ble_ll_conn_current_sm_over(void)
     /* Disable the wfr timer */
     ble_ll_wfr_disable();
 
-    /* Remove any scheduled items for this connection */
-    ble_ll_sched_rmv(BLE_LL_SCHED_TYPE_CONN, g_ble_ll_conn_cur_sm);
-
     /* Link-layer is in standby state now */
     ble_ll_state_set(BLE_LL_STATE_STANDBY);
 
@@ -214,9 +272,11 @@ ble_ll_conn_find_active_conn(uint16_t handle)
 {
     struct ble_ll_conn_sm *connsm;
 
-    SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) {
-        if (connsm->conn_handle == handle) {
-            break;
+    connsm = NULL;
+    if ((handle != 0) && (handle <= BLE_LL_CFG_CONN_MAX_CONNS)) {
+        connsm = &g_ble_ll_conn_sm[handle - 1];
+        if (connsm->conn_state == BLE_LL_CONN_STATE_IDLE) {
+            connsm = NULL;
         }
     }
     return connsm;
@@ -264,7 +324,7 @@ ble_ll_conn_calc_window_widening(struct ble_ll_conn_sm *connsm)
     if (time_since_last_anchor > 0) {
         delta_msec = cputime_ticks_to_usecs(time_since_last_anchor) / 1000;
         total_sca_ppm = g_ble_sca_ppm_tbl[connsm->master_sca] + 
-                        BLE_LL_CONN_CFG_OUR_SCA;
+                        BLE_LL_CFG_CONN_OUR_SCA;
         window_widening = (total_sca_ppm * delta_msec) / 1000;
     }
 
@@ -468,6 +528,7 @@ ble_ll_conn_wfr_timer_exp(void)
     struct ble_ll_conn_sm *connsm;
 
     connsm = g_ble_ll_conn_cur_sm;
+    ble_ll_conn_current_sm_over();
     if (connsm) {
         ble_ll_event_send(&connsm->conn_ev_end);
         ++g_ble_ll_conn_stats.wfr_expirations;
@@ -488,6 +549,8 @@ ble_ll_conn_wait_txend(void *arg)
 {
     struct ble_ll_conn_sm *connsm;
 
+    ble_ll_conn_current_sm_over();
+
     connsm = (struct ble_ll_conn_sm *)arg;
     ble_ll_event_send(&connsm->conn_ev_end);
 }
@@ -679,26 +742,6 @@ ble_ll_conn_tx_data_pdu(struct ble_ll_conn_sm *connsm, int beg_transition)
 }
 
 /**
- * Connection end schedule callback. Called when the scheduled connection 
- * event ends. 
- *  
- * Context: Interrupt 
- *  
- * @param sch 
- * 
- * @return int 
- */
-static int
-ble_ll_conn_ev_end_sched_cb(struct ble_ll_sched_item *sch)
-{
-    struct ble_ll_conn_sm *connsm;
-
-    connsm = (struct ble_ll_conn_sm *)sch->cb_arg;
-    ble_ll_event_send(&connsm->conn_ev_end);
-    return BLE_LL_SCHED_STATE_DONE;
-}
-
-/**
  * Schedule callback for start of connection event 
  *  
  * Context: Interrupt 
@@ -715,18 +758,19 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
     uint32_t wfr_time;
     struct ble_ll_conn_sm *connsm;
 
-    /* set led */
-    gpio_clear(LED_BLINK_PIN);
+    /* XXX: note that we can extend end time here if we want. Look at this */
 
     /* Set current connection state machine */
     connsm = (struct ble_ll_conn_sm *)sch->cb_arg;
     g_ble_ll_conn_cur_sm = connsm;
+    assert(connsm);
 
     /* Set LL state */
     ble_ll_state_set(BLE_LL_STATE_CONNECTION);
 
     /* Log connection event start */
-    ble_ll_log(BLE_LL_LOG_ID_CONN_EV_START, connsm->data_chan_index, 0, 0);
+    ble_ll_log(BLE_LL_LOG_ID_CONN_EV_START, connsm->data_chan_index, 0, 
+               connsm->ce_end_time);
 
     /* Set channel */
     rc = ble_phy_setchan(connsm->data_chan_index, connsm->access_addr, 
@@ -736,12 +780,9 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
     if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
         rc = ble_ll_conn_tx_data_pdu(connsm, BLE_PHY_TRANSITION_NONE);
         if (!rc) {
-            sch->next_wakeup = sch->end_time;
-            sch->sched_cb = ble_ll_conn_ev_end_sched_cb;
             rc = BLE_LL_SCHED_STATE_RUNNING;
         } else {
             /* Inform LL task of connection event end */
-            ble_ll_event_send(&connsm->conn_ev_end);
             rc = BLE_LL_SCHED_STATE_DONE;
         }
     } else {
@@ -749,7 +790,6 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
         if (rc) {
             /* End the connection event as we have no more buffers */
             ++g_ble_ll_conn_stats.slave_ce_failures;
-            ble_ll_event_send(&connsm->conn_ev_end);
             rc = BLE_LL_SCHED_STATE_DONE;
         } else {
             /* 
@@ -758,17 +798,32 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch)
              */ 
             connsm->slave_set_last_anchor = 1;
 
+            /* 
+             * Set the wait for response time. The anchor point is when we
+             * expect the master to start transmitting. Worst-case, we expect
+             * to hear a reply within the anchor point plus:
+             *  -> the current tx window size
+             *  -> The current window widening amount
+             *  -> Amount of time it takes to detect packet start.
+             */
             usecs = connsm->slave_cur_tx_win_usecs + BLE_LL_WFR_USECS +
                 connsm->slave_cur_window_widening;
             wfr_time = connsm->anchor_point + cputime_usecs_to_ticks(usecs);
             ble_ll_wfr_enable(wfr_time);
 
             /* Set next wakeup time to connection event end time */
-            sch->next_wakeup = sch->end_time;
-            sch->sched_cb = ble_ll_conn_ev_end_sched_cb;
             rc = BLE_LL_SCHED_STATE_RUNNING;
         }
     }
+
+    if (rc == BLE_LL_SCHED_STATE_DONE) {
+        ble_ll_event_send(&connsm->conn_ev_end);
+        ble_ll_state_set(BLE_LL_STATE_STANDBY);
+        g_ble_ll_conn_cur_sm = NULL;
+    }
+
+    /* Set time that we last serviced the schedule */
+    connsm->last_scheduled = cputime_get32();
     return rc;
 }
 
@@ -821,71 +876,6 @@ ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime)
 }
 
 /**
- * Set the schedule for connection events
- *  
- * Context: Link Layer task 
- * 
- * @param connsm 
- * 
- * @return struct ble_ll_sched_item * 
- */
-static struct ble_ll_sched_item *
-ble_ll_conn_sched_set(struct ble_ll_conn_sm *connsm)
-{
-    int rc;
-    uint32_t usecs;
-    struct ble_ll_sched_item *sch;
-
-    sch = ble_ll_sched_get_item();
-    if (sch) {
-        /* Set sched type, arg and callback function */
-        sch->sched_type = BLE_LL_SCHED_TYPE_CONN;
-        sch->cb_arg = connsm;
-        sch->sched_cb = ble_ll_conn_event_start_cb;
-
-        /* Set the start time of the event */
-        if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
-            sch->start_time = connsm->anchor_point - 
-                cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS);
-
-            /* We will attempt to schedule the maximum CE length */
-            usecs = connsm->max_ce_len * BLE_LL_CONN_CE_USECS;
-        } else {
-            /* Include window widening and scheduling delay */
-            usecs = connsm->slave_cur_window_widening +
-                XCVR_RX_SCHED_DELAY_USECS;
-
-            sch->start_time = connsm->anchor_point - 
-                cputime_usecs_to_ticks(usecs);
-
-            /* Schedule entire connection interval for slave */
-            usecs = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
-        }
-
-        /* 
-         * We must end at least an IFS before the next scheduled event to
-         * insure the minimum time between frames.
-         */
-        usecs -= (BLE_LL_IFS + BLE_LL_PROC_DELAY);
-        sch->end_time = connsm->anchor_point + cputime_usecs_to_ticks(usecs);
-        connsm->ce_end_time = sch->end_time;
-
-        /* XXX: for now, we cant get an overlap so assert on error. */
-        /* Add the item to the scheduler */
-        rc = ble_ll_sched_add(sch);
-        assert(rc == 0);
-    } else {
-        /* Count # of times we could not set schedule */
-        ++g_ble_ll_conn_stats.cant_set_sched;
-
-        /* XXX: for now just assert; must handle this later though */
-        assert(0);
-    }
-
-    return sch;
-}
-
-/**
  * Connection supervision timer callback; means that the connection supervision
  * timeout has been reached and we should perform the appropriate actions. 
  *  
@@ -915,11 +905,13 @@ void
 ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm, 
                         struct hci_create_conn *hcc)
 {
-    /* Must be master */
+    /* Set master role */
     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;
+
+    /* Set default ce parameters */
+    connsm->tx_win_size = BLE_LL_CFG_CONN_TX_WIN_SIZE;
+    connsm->tx_win_off = BLE_LL_CFG_CONN_TX_WIN_OFF;
+    connsm->master_sca = BLE_LL_CFG_CONN_MASTER_SCA;
 
     /* Hop increment is a random value between 5 and 16. */
     connsm->hop_inc = (rand() % 12) + 5;
@@ -962,17 +954,22 @@ ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm,
     /*  Calculate random access address and crc initialization value */
     connsm->access_addr = ble_ll_conn_calc_access_addr();
     connsm->crcinit = rand() & 0xffffff;
+
+    /* Set initial schedule callback */
+    connsm->conn_sch.sched_cb = ble_ll_conn_event_start_cb;
 }
 
 /**
- * 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, 
+ * Create a new 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. 
+ *  
+ * Context: Link Layer task 
  * 
  * @param connsm 
  */
 void
-ble_ll_conn_sm_start(struct ble_ll_conn_sm *connsm)
+ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm)
 {
     struct ble_ll_conn_global_params *conn_params;
 
@@ -1030,20 +1027,6 @@ ble_ll_conn_sm_start(struct ble_ll_conn_sm *connsm)
     connsm->eff_max_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN;
     connsm->eff_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN;
 
-    /* 
-     * Section 4.5.10 Vol 6 PART B. If the max tx/rx time or octets
-     * exceeds the minimum, data length procedure needs to occur
-     */
-    if ((connsm->max_tx_octets > BLE_LL_CONN_SUPP_BYTES_MIN) ||
-        (connsm->max_rx_octets > BLE_LL_CONN_SUPP_BYTES_MIN) ||
-        (connsm->max_tx_time > BLE_LL_CONN_SUPP_TIME_MIN) ||
-        (connsm->max_rx_time > BLE_LL_CONN_SUPP_TIME_MIN)) {
-        /* Start the data length update procedure */
-        if (ble_ll_read_supp_features() & BLE_LL_FEAT_DATA_LEN_EXT) {
-            ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD);
-        }
-    }
-
     /* Add to list of active connections */
     SLIST_INSERT_HEAD(&g_ble_ll_conn_active_list, connsm, act_sle);
 }
@@ -1114,13 +1097,8 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
     struct os_mbuf *m;
     struct os_mbuf_pkthdr *pkthdr;
 
-    /* If this is the current state machine, we need to end it */
-    if (connsm == g_ble_ll_conn_cur_sm) {
-        ble_ll_conn_current_sm_over();
-    } else {
-        /* Remove scheduler events just in case */
-        ble_ll_sched_rmv(BLE_LL_SCHED_TYPE_CONN, connsm);
-    }
+    /* Remove scheduler events just in case */
+    ble_ll_sched_rmv_elem(&connsm->conn_sch);
 
     /* Stop supervision timer */
     cputime_timer_stop(&connsm->conn_spvn_timer);
@@ -1173,6 +1151,75 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
     ble_ll_log(BLE_LL_LOG_ID_CONN_END,connsm->conn_handle,0,connsm->event_cntr);
 }
 
+static int
+ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
+{
+    uint16_t latency;
+    uint32_t itvl;
+    uint32_t cur_ww;
+    uint32_t max_ww;
+
+    /* 
+     * XXX: not quite sure I am interpreting slave latency correctly here.
+     * The spec says if you applied slave latency and you dont hear a packet,
+     * you dont apply slave latency. Does that mean you dont apply slave
+     * latency until you hear a packet or on the next interval if you listen
+     * and dont hear anything, can you apply slave latency?
+     */
+    /* Set event counter to the next connection event that we will tx/rx in */
+    itvl = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
+    latency = 1;
+    if (connsm->allow_slave_latency) {
+        if (connsm->pkt_rxd) {
+            latency += connsm->slave_latency;
+            itvl = itvl * latency;
+        }
+    }
+    connsm->event_cntr += latency;
+
+    /* Set next connection event start time */
+    connsm->anchor_point += cputime_usecs_to_ticks(itvl);
+
+    /* Calculate data channel index of next connection event */
+    connsm->last_unmapped_chan = connsm->unmapped_chan;
+    while (latency > 0) {
+        --latency;
+        connsm->data_chan_index = ble_ll_conn_calc_dci(connsm);
+    }
+
+    /* 
+     * If we are trying to terminate connection, check if next wake time is
+     * passed the termination timeout. If so, no need to continue with
+     * connection as we will time out anyway.
+     */
+    if (connsm->pending_ctrl_procs & (1 << BLE_LL_CTRL_PROC_TERMINATE)) {
+        if ((int32_t)(connsm->terminate_timeout - connsm->anchor_point) <= 0) {
+            return -1;
+        }
+    }
+
+    /* 
+     * Calculate ce end time. For a slave, we need to add window widening and
+     * the transmit window if we still have one.
+     */
+    itvl = BLE_LL_CFG_CONN_INIT_SLOTS * BLE_LL_SCHED_USECS_PER_SLOT;
+    if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
+        cur_ww = ble_ll_conn_calc_window_widening(connsm);
+        max_ww = (connsm->conn_itvl * (BLE_LL_CONN_ITVL_USECS/2)) - BLE_LL_IFS;
+        if (cur_ww >= max_ww) {
+            return -1;
+        }
+        connsm->slave_cur_window_widening = cur_ww;
+        itvl += cur_ww + connsm->slave_cur_tx_win_usecs;
+    } else {
+        /* We adjust end time for connection to end of time slot */
+        itvl -= XCVR_TX_SCHED_DELAY_USECS;
+    }
+    connsm->ce_end_time = connsm->anchor_point + cputime_usecs_to_ticks(itvl);
+
+    return 0;
+}
+
 /**
  * Called when a connection has been created. This function will 
  *  -> Set the connection state to created.
@@ -1185,10 +1232,13 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
  *  Context: Link Layer
  * 
  * @param connsm 
+ *  
+ * @ return 0: connection NOT created. 1: connection created 
  */
-static void
+static int
 ble_ll_conn_created(struct ble_ll_conn_sm *connsm, uint32_t endtime)
 {
+    int rc;
     uint32_t usecs;
 
     /* Set state to created */
@@ -1201,34 +1251,56 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, uint32_t endtime)
     /* Clear packet received flag */
     connsm->pkt_rxd = 0;
 
+    /* Consider time created the last scheduled time */
+    connsm->last_scheduled = cputime_get32();
+
     /* 
-     * Set first connection event time. If we are a master, the endtime
-     * represents the end of the advertisement that we are transmitting the
-     * connect request to. If a slave, it is the end time of connect request.
-     * Thus, for the master, we need to add an IFS time plus the time it takes
-     * to transmit the connection request. For both master and slave, the
-     * actual connection starts 1.25 msecs plus the transmit window offset
-     * from the end of the connection request.
+     * Set first connection event time. If slave the endtime is the receive end
+     * time of the connect request. The actual connection starts 1.25 msecs plus
+     * the transmit window offset from the end of the connection request.
      */
+    rc = 1;
     connsm->last_anchor_point = endtime;
-    if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) {
-        usecs = BLE_LL_CONN_REQ_DURATION + BLE_LL_IFS;
-        connsm->last_anchor_point += cputime_usecs_to_ticks(usecs);
-
-    } else {
+    if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
         connsm->slave_cur_tx_win_usecs = 
             connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS;
-        usecs = 0;
+        usecs = 1250 + (connsm->tx_win_off * BLE_LL_CONN_TX_WIN_USECS);
+        connsm->anchor_point = endtime + cputime_usecs_to_ticks(usecs);
+        usecs = connsm->slave_cur_tx_win_usecs + (BLE_LL_CFG_CONN_INIT_SLOTS *
+                                                  BLE_LL_SCHED_USECS_PER_SLOT);
+        connsm->ce_end_time = connsm->anchor_point + 
+            cputime_usecs_to_ticks(usecs);
+        connsm->slave_cur_window_widening = 0;
+
+        /* Start the scheduler for the first connection event */
+        while (ble_ll_sched_slave_new(connsm)) {
+            if (ble_ll_conn_next_event(connsm)) {
+                ++g_ble_ll_conn_stats.cant_set_sched;
+                rc = 0;
+                break;
+            }
+        }
     }
-    usecs += 1250 + (connsm->tx_win_off * BLE_LL_CONN_TX_WIN_USECS);
-    connsm->anchor_point = endtime + cputime_usecs_to_ticks(usecs);
-    connsm->slave_cur_window_widening = 0;
 
     /* Send connection complete event to inform host of connection */
-    ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS);
+    if (rc) {
+        /* 
+         * Section 4.5.10 Vol 6 PART B. If the max tx/rx time or octets
+         * exceeds the minimum, data length procedure needs to occur
+         */
+        if ((connsm->max_tx_octets > BLE_LL_CONN_SUPP_BYTES_MIN) ||
+            (connsm->max_rx_octets > BLE_LL_CONN_SUPP_BYTES_MIN) ||
+            (connsm->max_tx_time > BLE_LL_CONN_SUPP_TIME_MIN) ||
+            (connsm->max_rx_time > BLE_LL_CONN_SUPP_TIME_MIN)) {
+            /* Start the data length update procedure */
+            if (ble_ll_read_supp_features() & BLE_LL_FEAT_DATA_LEN_EXT) {
+                ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD);
+            }
+        }
+        ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS);
+    }
 
-    /* Start the scheduler for the first connection event */
-    ble_ll_conn_sched_set(connsm);
+    return rc;
 }
 
 /**
@@ -1243,17 +1315,18 @@ void
 ble_ll_conn_event_end(void *arg)
 {
     uint8_t ble_err;
-    uint16_t latency;
-    uint32_t itvl;
-    uint32_t cur_ww;
-    uint32_t max_ww;
     struct ble_ll_conn_sm *connsm;
 
+    /* Better be a connection state machine! */
     connsm = (struct ble_ll_conn_sm *)arg;
-    assert(connsm && (connsm == g_ble_ll_conn_cur_sm));
+    assert(connsm);
 
-    /* The current state machine is over */
-    ble_ll_conn_current_sm_over();
+    /* Check if we need to resume scanning */
+    ble_ll_scan_chk_resume();
+
+    /* Log event end */
+    ble_ll_log(BLE_LL_LOG_ID_CONN_EV_END, 0, connsm->event_cntr, 
+               connsm->ce_end_time);
 
     /* If we have transmitted the terminate IND successfully, we are done */
     if ((connsm->terminate_ind_txd) || (connsm->terminate_ind_rxd)) {
@@ -1281,79 +1354,30 @@ ble_ll_conn_event_end(void *arg)
         connsm->slave_cur_tx_win_usecs = 0;
     }
 
-    /* 
-     * XXX: not quite sure I am interpreting slave latency correctly here.
-     * The spec says if you applied slave latency and you dont hear a packet,
-     * you dont apply slave latency. Does that mean you dont apply slave
-     * latency until you hear a packet or on the next interval if you listen
-     * and dont hear anything, can you apply slave latency?
-     */
-    /* Set event counter to the next connection event that we will tx/rx in */
-    itvl = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS;
-    latency = 1;
-    if (connsm->allow_slave_latency) {
-        if (connsm->pkt_rxd) {
-            latency += connsm->slave_latency;
-            itvl = itvl * latency;
-        }
-    }
-    connsm->event_cntr += latency;
-
-    /* Set next connection event start time */
-    connsm->anchor_point += cputime_usecs_to_ticks(itvl);
-
-    /* Calculate data channel index of next connection event */
-    connsm->last_unmapped_chan = connsm->unmapped_chan;
-    while (latency > 0) {
-        --latency;
-        connsm->data_chan_index = ble_ll_conn_calc_dci(connsm);
-    }
-
-    /* We better not be late for the anchor point. If so, skip events */
-    while ((int32_t)(connsm->anchor_point - cputime_get32()) <= 0) {
-        ++connsm->event_cntr;
-        connsm->data_chan_index = ble_ll_conn_calc_dci(connsm);
-        connsm->anchor_point += 
-            cputime_usecs_to_ticks(connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS);
-        ++g_ble_ll_conn_stats.conn_ev_late;
+    /* Move to next connection event */
+    if (ble_ll_conn_next_event(connsm)) {
+        ble_ll_conn_end(connsm, BLE_ERR_CONN_TERM_LOCAL);
+        return;
     }
 
     /* Reset "per connection event" variables */
     connsm->cons_rxd_bad_crc = 0;
     connsm->pkt_rxd = 0;
 
-    /* 
-     * If we are trying to terminate connection, check if next wake time is
-     * passed the termination timeout. If so, no need to continue with
-     * connection as we will time out anyway.
-     */
-    if (connsm->pending_ctrl_procs & (1 << BLE_LL_CTRL_PROC_TERMINATE)) {
-        if ((int32_t)(connsm->terminate_timeout - connsm->anchor_point) <= 0) {
-            ble_ll_conn_end(connsm, BLE_ERR_CONN_TERM_LOCAL);
-            return;
-        }
-    }
+    /* See if we need to start any control procedures */
+    ble_ll_ctrl_chk_proc_start(connsm);
 
-    /* Calculate window widening for next event. If too big, end conn */
-    if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
-        cur_ww = ble_ll_conn_calc_window_widening(connsm);
-        max_ww = (connsm->conn_itvl * (BLE_LL_CONN_ITVL_USECS/2)) - BLE_LL_IFS;
-        if (cur_ww >= max_ww) {
+    /* Set initial schedule callback */
+    connsm->conn_sch.sched_cb = ble_ll_conn_event_start_cb;
+
+    /* Schedule the next connection event */
+    while (ble_ll_sched_conn_reschedule(connsm)) {
+        if (ble_ll_conn_next_event(connsm)) {
             ble_ll_conn_end(connsm, BLE_ERR_CONN_TERM_LOCAL);
             return;
         }
-        connsm->slave_cur_window_widening = cur_ww;
     }
 
-    /* Log event end */
-    ble_ll_log(BLE_LL_LOG_ID_CONN_EV_END, 0, 0, connsm->event_cntr);
-
-    /* See if we need to start any control procedures */
-    ble_ll_ctrl_chk_proc_start(connsm);
-
-    /* Schedule the next connection event */
-    ble_ll_conn_sched_set(connsm);
-
     /* If we have completed packets, send an event */
     if (connsm->completed_pkts) {
         ble_ll_conn_num_comp_pkts_event_send();
@@ -1367,9 +1391,11 @@ ble_ll_conn_event_end(void *arg)
  * @param m 
  * @param adva 
  * @param addr_type 
+ * @param txoffset      The tx window offset for this connection 
  */
-void
-ble_ll_conn_req_pdu_update(struct os_mbuf *m, uint8_t *adva, uint8_t addr_type)
+static void
+ble_ll_conn_req_pdu_update(struct os_mbuf *m, uint8_t *adva, uint8_t addr_type,
+                           uint16_t txoffset)
 {
     uint8_t pdu_type;
     uint8_t *dptr;
@@ -1391,7 +1417,8 @@ ble_ll_conn_req_pdu_update(struct os_mbuf *m, uint8_t *adva, uint8_t addr_type)
     ble_hdr->txinfo.hdr_byte = pdu_type;
 
     dptr = m->om_data;
-    memcpy(dptr + BLE_DEV_ADDR_LEN, adva, BLE_DEV_ADDR_LEN); 
+    memcpy(dptr + BLE_DEV_ADDR_LEN, adva, BLE_DEV_ADDR_LEN);
+    htole16(dptr + 20, txoffset);
 }
 
 /* Returns true if the address matches the connection peer address */
@@ -1414,6 +1441,19 @@ ble_ll_conn_is_peer_adv(uint8_t addr_type, uint8_t *adva)
 }
 
 /**
+ * Called when a connect request transmission is done. 
+ *  
+ * Context: ISR 
+ * 
+ * @param arg 
+ */
+static void
+ble_ll_conn_req_txend(void *arg)
+{
+    ble_ll_state_set(BLE_LL_STATE_STANDBY);
+}
+
+/**
  * Send a connection requestion to an advertiser 
  *  
  * Context: Interrupt 
@@ -1422,18 +1462,38 @@ ble_ll_conn_is_peer_adv(uint8_t addr_type, uint8_t *adva)
  * @param adva Address of advertiser
  */
 static int
-ble_ll_conn_request_send(uint8_t addr_type, uint8_t *adva)
+ble_ll_conn_request_send(uint8_t addr_type, uint8_t *adva, uint16_t txoffset)
 {
     int rc;
     struct os_mbuf *m;
 
     m = ble_ll_scan_get_pdu();
-    ble_ll_conn_req_pdu_update(m, adva, addr_type);
+    ble_ll_conn_req_pdu_update(m, adva, addr_type, txoffset);
+    ble_phy_set_txend_cb(ble_ll_conn_req_txend, NULL);
     rc = ble_phy_tx(m, BLE_PHY_TRANSITION_RX_TX, BLE_PHY_TRANSITION_NONE);
     return rc;
 }
 
 /**
+ * Called when a schedule item overlaps the currently running connection 
+ * event. This generally should not happen, but if it does we stop the 
+ * current connection event to let the schedule item run. 
+ *  
+ * NOTE: the phy has been disabled as well as the wfr timer before this is 
+ * called. 
+ */
+void
+ble_ll_conn_event_halt(void)
+{
+    ble_ll_state_set(BLE_LL_STATE_STANDBY);
+    if (g_ble_ll_conn_cur_sm) {
+        g_ble_ll_conn_cur_sm->pkt_rxd = 0;
+        ble_ll_event_send(&g_ble_ll_conn_cur_sm->conn_ev_end);
+        g_ble_ll_conn_cur_sm = NULL;
+    }
+}
+
+/**
  * Process a received PDU while in the initiating state.
  *  
  * Context: Link Layer task. 
@@ -1449,12 +1509,9 @@ ble_ll_init_rx_pkt_in(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr)
 
     /* Get the connection state machine we are trying to create */
     connsm = g_ble_ll_conn_create_sm;
-    if (!connsm) {
-        return;
-    }
 
     /* If we have sent a connect request, we need to enter CONNECTION state*/
-    if (ble_hdr->rxinfo.crcok && 
+    if (connsm && BLE_MBUF_HDR_CRC_OK(ble_hdr) && 
         (ble_hdr->rxinfo.flags & BLE_MBUF_HDR_F_CONN_REQ_TXD)) {
         /* Set address of advertiser to which we are connecting. */
         if (!ble_ll_scan_whitelist_enabled()) {
@@ -1477,15 +1534,15 @@ ble_ll_init_rx_pkt_in(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr)
 
         /* Connection has been created. Stop scanning */
         g_ble_ll_conn_create_sm = NULL;
-        ble_ll_scan_sm_stop(ble_ll_scan_sm_get(), 1);
+        ble_ll_scan_sm_stop(0);
         ble_ll_conn_created(connsm, ble_hdr->end_cputime);
     } else {
-        ble_ll_scan_resume();
+        ble_ll_scan_chk_resume();
     }
 }
 
 /**
- * Called when a receive PDU has ended. 
+ * Called when a receive PDU has ended and we are in the initiating state.
  *  
  * Context: Interrupt 
  * 
@@ -1497,7 +1554,7 @@ ble_ll_init_rx_pkt_in(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr)
  *       > 0: Do not disable PHY as that has already been done.
  */
 int
-ble_ll_init_rx_pdu_end(struct os_mbuf *rxpdu)
+ble_ll_init_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok)
 {
     int rc;
     int chk_send_req;
@@ -1508,6 +1565,20 @@ ble_ll_init_rx_pdu_end(struct os_mbuf *rxpdu)
     uint8_t *rxbuf;
     struct ble_mbuf_hdr *ble_hdr;
 
+    /* 
+     * We have to restart receive if we cant hand up pdu. We return 0 so that
+     * the phy does not get disabled.
+     */
+    if (!rxpdu) {
+        ble_phy_rx();
+        return 0;
+    }
+
+    rc = -1;
+    if (!crcok) {
+        goto init_rx_isr_exit;
+    }
+
     /* Only interested in ADV IND or ADV DIRECT IND */
     rxbuf = rxpdu->om_data;
     pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK;
@@ -1531,7 +1602,6 @@ ble_ll_init_rx_pdu_end(struct os_mbuf *rxpdu)
     }
 
     /* Should we send a connect request? */
-    rc = -1;
     if (chk_send_req) {
         /* Check filter policy */
         adv_addr = rxbuf + BLE_LL_PDU_HDR_LEN;
@@ -1560,18 +1630,63 @@ ble_ll_init_rx_pdu_end(struct os_mbuf *rxpdu)
             }
         }
 
-        /* Setup to transmit the connect request */
-        rc = ble_ll_conn_request_send(addr_type, adv_addr);
-        if (!rc) {
-            ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CONN_REQ_TXD;
-            ++g_ble_ll_conn_stats.conn_req_txd;
+        /* Attempt to schedule new connection. Possible that this might fail */
+        if (!ble_ll_sched_master_new(g_ble_ll_conn_create_sm, 
+                                   ble_hdr->end_cputime,
+                                   BLE_LL_CFG_CONN_INIT_SLOTS)) {
+            /* Setup to transmit the connect request */
+            rc = ble_ll_conn_request_send(addr_type, adv_addr, 
+                                          g_ble_ll_conn_create_sm->tx_win_off);
+            if (!rc) {
+                ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CONN_REQ_TXD;
+                ++g_ble_ll_conn_stats.conn_req_txd;
+            }
+        } else {
+            /* Count # of times we could not set schedule */
+            ++g_ble_ll_conn_stats.cant_set_sched;
         }
     }
 
+init_rx_isr_exit:
+    if (rc) {
+        ble_ll_state_set(BLE_LL_STATE_STANDBY);
+    }
     return rc;
 }
 
 /**
+ * Function called when a timeout has occurred for a connection. There are 
+ * two types of timeouts: a connection supervision timeout and control 
+ * procedure timeout. 
+ *  
+ * Context: Link Layer task 
+ * 
+ * @param connsm 
+ * @param ble_err 
+ */
+void
+ble_ll_conn_timeout(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
+{
+    int was_current;
+    os_sr_t sr;
+
+    was_current = 0;
+    OS_ENTER_CRITICAL(sr);
+    if (g_ble_ll_conn_cur_sm == connsm) {
+        ble_ll_conn_current_sm_over();
+        was_current = 1;
+    }
+    OS_EXIT_CRITICAL(sr);
+
+    /* Check if we need to resume scanning */
+    if (was_current) {
+        ble_ll_scan_chk_resume();
+    }
+
+    ble_ll_conn_end(connsm, ble_err);
+}
+
+/**
  * Connection supervision timeout. When called, it means that the connection 
  * supervision timeout has been reached. If reached, we end the connection. 
  *  
@@ -1582,16 +1697,18 @@ ble_ll_init_rx_pdu_end(struct os_mbuf *rxpdu)
 void
 ble_ll_conn_spvn_timeout(void *arg)
 {
-    ble_ll_conn_end((struct ble_ll_conn_sm *)arg, BLE_ERR_CONN_SPVN_TMO);
+    ble_ll_conn_timeout((struct ble_ll_conn_sm *)arg, BLE_ERR_CONN_SPVN_TMO);
 }
 
 /**
  * Called when a data channel PDU has started that matches the access 
  * address of the current connection. Note that the CRC of the PDU has not 
- * been checked yet.
+ * been checked yet. 
+ *  
+ * Context: Interrupt 
  */
 void
-ble_ll_conn_rx_pdu_start(void)
+ble_ll_conn_rx_isr_start(void)
 {
     struct ble_ll_conn_sm *connsm;
 
@@ -1613,10 +1730,11 @@ ble_ll_conn_rx_pdu_start(void)
  *  
  * Context: Link layer task 
  * 
- * @param rxpdu 
+ * @param rxpdu Pointer to received pdu
+ * @param rxpdu Pointer to ble mbuf header of received pdu
  */
 void
-ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, uint8_t crcok)
+ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
 {
     uint8_t hdr_byte;
     uint8_t rxd_sn;
@@ -1625,13 +1743,15 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, uint8_t crcok)
     uint16_t acl_hdr;
     uint32_t tmo;
     struct ble_ll_conn_sm *connsm;
-
-    if (crcok) {
+    
+    if (BLE_MBUF_HDR_CRC_OK(hdr)) {
         /* Count valid received data pdus */
         ++g_ble_ll_stats.rx_valid_data_pdus;
 
+        /* XXX: there is a chance that the connection was thrown away and
+           re-used before processing packets here. Fix this. */
         /* We better have a connection state machine */
-        connsm = g_ble_ll_conn_cur_sm;
+        connsm = ble_ll_conn_find_active_conn(hdr->rxinfo.handle);
         if (connsm) {
             /* Reset the connection supervision timeout */
             cputime_timer_stop(&connsm->conn_spvn_timer);
@@ -1724,7 +1844,7 @@ conn_rx_data_pdu_end:
  *       > 0: Do not disable PHY as that has already been done.
  */
 int
-ble_ll_conn_rx_pdu_end(struct os_mbuf *rxpdu, uint32_t aa)
+ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu, uint32_t aa)
 {
     int rc;
     uint8_t hdr_byte;
@@ -1744,26 +1864,29 @@ ble_ll_conn_rx_pdu_end(struct os_mbuf *rxpdu, uint32_t aa)
      * We should have a current connection state machine. If we dont, we just
      * hand the packet to the higher layer to count it.
      */
+    rc = -1;
     connsm = g_ble_ll_conn_cur_sm;
     if (!connsm) {
         ++g_ble_ll_conn_stats.rx_data_pdu_no_conn;
-        return -1;
+        goto conn_exit;
     }
 
     /* Double check access address. Better match connection state machine! */
     if (aa != connsm->access_addr) {
         ++g_ble_ll_conn_stats.rx_data_pdu_bad_aa;
-        ble_ll_event_send(&connsm->conn_ev_end);
-        return -1;
+        goto conn_exit;
     }
 
+    /* Set the handle in the ble mbuf header */
+    rxhdr = BLE_MBUF_HDR_PTR(rxpdu);
+    rxhdr->rxinfo.handle = connsm->conn_handle;
+
     /* 
      * Check the packet CRC. A connection event can continue even if the
      * received PDU does not pass the CRC check. If we receive two consecutive
      * CRC errors we end the conection event.
      */
-    rxhdr = BLE_MBUF_HDR_PTR(rxpdu);
-    if (!rxhdr->rxinfo.crcok) {
+    if (!BLE_MBUF_HDR_CRC_OK(rxhdr)) {
         /* 
          * Increment # of consecutively received CRC errors. If more than
          * one we will end the connection event.
@@ -1894,19 +2017,24 @@ ble_ll_conn_rx_pdu_end(struct os_mbuf *rxpdu, uint32_t aa)
     }
 
 conn_rx_pdu_end:
-    /* Set last anchor point if 1st received frame in connection event */
+    /* Set anchor point (and last) if 1st received frame in connection event */
     if (connsm->slave_set_last_anchor) {
         connsm->slave_set_last_anchor = 0;
         connsm->last_anchor_point = rxhdr->end_cputime - 
             BLE_TX_DUR_USECS_M(rxpdu->om_data[1]);
+        connsm->anchor_point = connsm->last_anchor_point;
     }
 
     /* Send link layer a connection end event if over */
+conn_exit:
     if (rc) {
-        ble_ll_event_send(&connsm->conn_ev_end);
+        ble_ll_conn_current_sm_over();
+        if (connsm) {
+            ble_ll_event_send(&connsm->conn_ev_end);
+        }
     }
 
-    return 0;
+    return rc;
 }
 
 /**
@@ -1999,12 +2127,14 @@ ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t length)
  * Context: Link Layer 
  *  
  * @param rxbuf Pointer to received PDU 
+ * @param conn_req_end receive end time of connect request 
  *  
  * @return 0: connection not started; 1 connecton started 
  */
 int
 ble_ll_conn_slave_start(uint8_t *rxbuf, uint32_t conn_req_end)
 {
+    int rc;
     uint32_t temp;
     uint32_t crcinit;
     uint8_t *inita;
@@ -2096,11 +2226,17 @@ ble_ll_conn_slave_start(uint8_t *rxbuf, uint32_t conn_req_end)
 
     /* Start the connection state machine */
     connsm->conn_role = BLE_LL_CONN_ROLE_SLAVE;
-    ble_ll_conn_sm_start(connsm);
+    ble_ll_conn_sm_new(connsm);
 
-    /* The connection has been created. */
-    ble_ll_conn_created(connsm, conn_req_end);
-    return 1;
+    /* Set initial schedule callback */
+    connsm->conn_sch.sched_cb = ble_ll_conn_event_start_cb;
+
+    rc = ble_ll_conn_created(connsm, conn_req_end);
+    if (!rc) {
+        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);
+    }
+    return rc;
 
 err_slave_start:
     STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe);
@@ -2109,7 +2245,9 @@ err_slave_start:
 }
 
 /**
- * Called to reset the connection module.
+ * Called to reset the connection module. When this function is called the 
+ * scheduler has been stopped and the phy has been disabled. The LL should 
+ * be in the standby state. 
  *  
  * Context: Link Layer task 
  */
@@ -2121,7 +2259,7 @@ ble_ll_conn_reset(void)
     /* Kill the current one first (if one is running) */
     if (g_ble_ll_conn_cur_sm) {
         connsm = g_ble_ll_conn_cur_sm;
-        ble_ll_conn_current_sm_over();
+        g_ble_ll_conn_cur_sm = NULL;
         ble_ll_conn_end(connsm, BLE_ERR_SUCCESS);
     }
 
@@ -2155,7 +2293,7 @@ ble_ll_conn_module_init(void)
      * the specification allows a handle of zero; we just avoid using it.
      */
     connsm = &g_ble_ll_conn_sm[0];
-    for (i = 0; i < BLE_LL_CONN_CFG_MAX_CONNS; ++i) {
+    for (i = 0; i < BLE_LL_CFG_CONN_MAX_CONNS; ++i) {
         connsm->conn_handle = i + 1;
         STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe);
 
@@ -2170,6 +2308,9 @@ ble_ll_conn_module_init(void)
 
         ble_ll_mbuf_init(m, 0, BLE_LL_LLID_DATA_FRAG);
 
+        /* Initialize fixed schedule elements */
+        connsm->conn_sch.sched_type = BLE_LL_SCHED_TYPE_CONN;
+        connsm->conn_sch.cb_arg = connsm;
         ++connsm;
     }
 
@@ -2187,3 +2328,4 @@ ble_ll_conn_module_init(void)
     conn_params->conn_init_max_tx_time = BLE_TX_DUR_USECS_M(maxbytes);
     conn_params->conn_init_max_tx_octets = BLE_LL_CFG_CONN_INIT_MAX_TX_BYTES;
 }
+

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/net/nimble/controller/src/ble_ll_conn_hci.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn_hci.c b/net/nimble/controller/src/ble_ll_conn_hci.c
index a4ac46c..a051318 100644
--- a/net/nimble/controller/src/ble_ll_conn_hci.c
+++ b/net/nimble/controller/src/ble_ll_conn_hci.c
@@ -358,7 +358,7 @@ ble_ll_conn_create(uint8_t *cmdbuf)
 
     /* Initialize state machine in master role and start state machine */
     ble_ll_conn_master_init(connsm, hcc);
-    ble_ll_conn_sm_start(connsm);
+    ble_ll_conn_sm_new(connsm);
 
     /* Create the connection request */
     ble_ll_conn_req_pdu_make(connsm);
@@ -400,7 +400,7 @@ ble_ll_conn_create_cancel(void)
     if (connsm && (connsm->conn_state == BLE_LL_CONN_STATE_IDLE)) {
         /* stop scanning and end the connection event */
         g_ble_ll_conn_create_sm = NULL;
-        ble_ll_scan_sm_stop(ble_ll_scan_sm_get(), 0);
+        ble_ll_scan_sm_stop(1);
         ble_ll_conn_end(connsm, BLE_ERR_UNK_CONN_ID);
         rc = BLE_ERR_SUCCESS;
     } else {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/net/nimble/controller/src/ble_ll_conn_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn_priv.h b/net/nimble/controller/src/ble_ll_conn_priv.h
index 48304b2..47015a3 100644
--- a/net/nimble/controller/src/ble_ll_conn_priv.h
+++ b/net/nimble/controller/src/ble_ll_conn_priv.h
@@ -32,6 +32,7 @@
 #define BLE_LL_CONN_SUPP_BYTES_MAX          (251)   /* bytes */
 
 /* Connection event timing */
+#define BLE_LL_CONN_INITIAL_OFFSET          (1250)
 #define BLE_LL_CONN_ITVL_USECS              (1250)
 #define BLE_LL_CONN_TX_WIN_USECS            (1250)
 #define BLE_LL_CONN_CE_USECS                (625)
@@ -60,7 +61,7 @@ extern struct ble_ll_conn_sm *g_ble_ll_conn_create_sm;
 struct ble_ll_len_req;
 struct hci_create_conn;
 struct ble_mbuf_hdr;
-void ble_ll_conn_sm_start(struct ble_ll_conn_sm *connsm);
+void ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm);
 void ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err);
 void ble_ll_conn_enqueue_pkt(struct ble_ll_conn_sm *connsm, struct os_mbuf *om,
                              uint8_t hdr_byte, uint8_t length);
@@ -80,12 +81,15 @@ void ble_ll_conn_reset(void);
 void ble_ll_conn_event_end(void *arg);
 void ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t len);
 void ble_ll_conn_spvn_timeout(void *arg);
-void ble_ll_conn_rx_pdu_start(void);
-int ble_ll_conn_rx_pdu_end(struct os_mbuf *rxpdu, uint32_t aa);
-void ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, uint8_t crcok);
+void ble_ll_conn_rx_isr_start(void);
+int ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu, uint32_t aa);
+void ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr);
 void ble_ll_init_rx_pkt_in(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr);
-int ble_ll_init_rx_pdu_end(struct os_mbuf *rxpdu);
+int ble_ll_init_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok);
 void ble_ll_conn_wfr_timer_exp(void);
+int ble_ll_conn_is_lru(struct ble_ll_conn_sm *s1, struct ble_ll_conn_sm *s2);
+uint32_t ble_ll_conn_get_ce_end_time(void);
+void ble_ll_conn_event_halt(void);
 
 /* HCI */
 void ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm *connsm, 
@@ -96,5 +100,7 @@ int ble_ll_conn_create(uint8_t *cmdbuf);
 int ble_ll_conn_create_cancel(void);
 void ble_ll_conn_num_comp_pkts_event_send(void);
 void ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status);
+void ble_ll_conn_timeout(struct ble_ll_conn_sm *connsm, uint8_t ble_err);
+
 
 #endif /* H_BLE_LL_CONN_PRIV_ */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-larva/blob/b6e2b5ff/net/nimble/controller/src/ble_ll_ctrl.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_ctrl.c b/net/nimble/controller/src/ble_ll_ctrl.c
index 2a06265..0e5df2d 100644
--- a/net/nimble/controller/src/ble_ll_ctrl.c
+++ b/net/nimble/controller/src/ble_ll_ctrl.c
@@ -197,7 +197,7 @@ void
 ble_ll_ctrl_proc_rsp_timer_cb(void *arg)
 {
     /* Control procedure has timed out. Kill the connection */
-    ble_ll_conn_end((struct ble_ll_conn_sm *)arg, BLE_ERR_LMP_LL_RSP_TMO);
+    ble_ll_conn_timeout((struct ble_ll_conn_sm *)arg, BLE_ERR_LMP_LL_RSP_TMO);
 }
 
 /**