Initial commit for the "body sensor network" code changes.

X-Original-Commit: 4d4c3e18284af0d2bd2e085c89c71078c5d0d01c
This commit is contained in:
William San Filippo
2017-07-18 09:56:55 -07:00
parent 429a11ffb2
commit 085095077b
6 changed files with 336 additions and 1 deletions
@@ -213,6 +213,13 @@ struct ble_ll_conn_sm
uint8_t last_unmapped_chan;
uint8_t num_used_chans;
#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
uint8_t period_occ_mask; /* mask: period 0 = 0x01, period 3 = 0x08 */
#endif
/* RSSI */
int8_t conn_rssi;
/* Ack/Flow Control */
uint8_t tx_seqnum; /* note: can be 1 bit */
uint8_t next_exp_seqnum; /* note: can be 1 bit */
@@ -77,6 +77,40 @@ extern uint8_t g_ble_ll_sched_offset_ticks;
struct ble_ll_sched_item;
typedef int (*sched_cb_func)(struct ble_ll_sched_item *sch);
/*
* Strict connection scheduling (for the master) is different than how
* connections are normally scheduled. With strict connection scheduling we
* introduce the concept of a "period". A period is a collection of slots. Each
* slot is 1.25 msecs in length. The number of slots in a period is determined
* by the syscfg value BLE_LL_CONN_INIT_SLOTS. A collection of periods is called
* an epoch. The length of an epoch is determined by the number of connections
* (BLE_MAX_CONNECTIONS plus BLE_LL_ADD_STRICT_SCHED_PERIODS). Connections
* will be scheduled at period boundaries. Any scanning/initiating/advertising
* will be done in unused periods, if possible.
*/
#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
#define BLE_LL_SCHED_PERIODS (MYNEWT_VAL(BLE_MAX_CONNECTIONS) + \
MYNEWT_VAL(BLE_LL_ADD_STRICT_SCHED_PERIODS))
struct ble_ll_sched_obj
{
uint8_t sch_num_occ_periods;
uint32_t sch_occ_period_mask;
uint32_t sch_ticks_per_period;
uint32_t sch_ticks_per_epoch;
uint32_t sch_epoch_start;
};
extern struct ble_ll_sched_obj g_ble_ll_sched_data;
/*
* XXX: TODO:
* -> How do we know epoch start is up to date? Not wrapped?
* -> for now, only do this with no more than 32 connections.
* -> Do not let initiating occur if no empty sched slots
*/
#endif
/*
* Schedule item
* sched_type: This is the type of the schedule item.
+3
View File
@@ -1195,6 +1195,9 @@ ble_ll_reset(void)
/* All this does is re-initialize the event masks so call the hci init */
ble_ll_hci_init();
/* Reset scheduler */
ble_ll_sched_init();
/* Set state to standby */
ble_ll_state_set(BLE_LL_STATE_STANDBY);
+25 -1
View File
@@ -2021,6 +2021,9 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
uint8_t *evbuf;
struct os_mbuf *m;
struct os_mbuf_pkthdr *pkthdr;
#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
os_sr_t sr;
#endif
/* Remove scheduler events just in case */
ble_ll_sched_rmv_elem(&connsm->conn_sch);
@@ -2057,6 +2060,16 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
/* Make sure events off queue */
os_eventq_remove(&g_ble_ll_data.ll_evq, &connsm->conn_ev_end);
#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
/* Remove from occupied periods */
OS_ENTER_CRITICAL(sr);
assert(g_ble_ll_sched_data.sch_num_occ_periods > 0);
assert(g_ble_ll_sched_data.sch_occ_period_mask & connsm->period_occ_mask);
--g_ble_ll_sched_data.sch_num_occ_periods;
g_ble_ll_sched_data.sch_occ_period_mask &= ~connsm->period_occ_mask;
OS_EXIT_CRITICAL(sr);
#endif
/* Connection state machine is now idle */
connsm->conn_state = BLE_LL_CONN_STATE_IDLE;
@@ -2101,7 +2114,8 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe);
/* Log connection end */
ble_ll_log(BLE_LL_LOG_ID_CONN_END,connsm->conn_handle,0,connsm->event_cntr);
ble_ll_log(BLE_LL_LOG_ID_CONN_END,connsm->conn_handle, ble_err,
connsm->event_cntr);
}
/**
@@ -2294,7 +2308,11 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm)
* Calculate ce end time. For a slave, we need to add window widening and
* the transmit window if we still have one.
*/
#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
itvl = g_ble_ll_sched_data.sch_ticks_per_period;
#else
itvl = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT;
#endif
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;
@@ -2397,10 +2415,16 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr)
connsm->slave_cur_tx_win_usecs =
connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS;
#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
connsm->ce_end_time = connsm->anchor_point +
g_ble_ll_sched_data.sch_ticks_per_period +
os_cputime_usecs_to_ticks(connsm->slave_cur_tx_win_usecs) + 1;
#else
connsm->ce_end_time = connsm->anchor_point +
(MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT)
+ os_cputime_usecs_to_ticks(connsm->slave_cur_tx_win_usecs) + 1;
#endif
connsm->slave_cur_window_widening = BLE_LL_JITTER_USECS;
/* Start the scheduler for the first connection event */
+246
View File
@@ -65,6 +65,10 @@ int32_t g_ble_ll_sched_max_early;
/* Queue for timers */
TAILQ_HEAD(ll_sched_qhead, ble_ll_sched_item) g_ble_ll_sched_q;
#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
struct ble_ll_sched_obj g_ble_ll_sched_data;
#endif
/**
* Checks if two events in the schedule will overlap in time. NOTE: consecutive
* schedule items can end and start at the same time.
@@ -295,6 +299,238 @@ ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm)
*
* @return int
*/
#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
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;
int i;
uint32_t tpp;
uint32_t tse;
uint32_t np;
uint32_t cp;
uint32_t tick_in_period;
struct ble_ll_sched_item *entry;
struct ble_ll_sched_item *sch;
/* Better have a connsm */
assert(connsm != NULL);
/* Get schedule element from connection */
rc = -1;
sch = &connsm->conn_sch;
/* XXX:
* The calculations for the 32kHz crystal bear alot of explanation. The
* earliest possible time that the master can start the connection with a
* slave is 1.25 msecs from the end of the connection request. The
* connection request is sent an IFS time from the end of the advertising
* packet that was received plus the time it takes to send the connection
* request. At 1 Mbps, this is 1752 usecs, or 57.41 ticks. Using 57 ticks
* makes us off ~13 usecs. Since we dont want to actually calculate the
* receive end time tick (this would take too long), we assume the end of
* the advertising PDU is 'now' (we call os_cputime_get32). We dont know
* how much time it will take to service the ISR but if we are more than the
* rx to tx time of the chip we will not be successful transmitting the
* connect request. All this means is that we presume that the slave will
* receive the connect request later than we expect but no earlier than
* 13 usecs before (this is important).
*
* The code then attempts to schedule the connection at the
* earliest time although this may not be possible. When the actual
* schedule start time is determined, the master has to determine if this
* time is more than a transmit window offset interval (1.25 msecs). The
* master has to tell the slave how many transmit window offsets there are
* from the earliest possible time to when the actual transmit start will
* occur. Later in this function you will see the calculation. The actual
* transmission start has to occur within the transmit window. The transmit
* window interval is in units of 1.25 msecs and has to be at least 1. To
* make things a bit easier (but less power efficient for the slave), we
* use a transmit window of 2. We do this because we dont quite know the
* exact start of the transmission and if we are too early or too late we
* could miss the transmit window. A final note: the actual transmission
* start (the anchor point) is sched offset ticks from the schedule start
* time. We dont add this to the calculation when calculating the window
* offset. The reason we dont do this is we want to insure we transmit
* after the window offset we tell the slave. For example, say we think
* we are transmitting 1253 usecs from the earliest start. This would cause
* us to send a transmit window offset of 1. Since we are actually
* transmitting earlier than the slave thinks we could end up transmitting
* before the window offset. Transmitting later is fine since we have the
* transmit window to do so. Transmitting before is bad, since the slave
* wont be listening. We could do better calculation if we wanted to use
* a transmit window of 1 as opposed to 2, but for now we dont care.
*/
dur = os_cputime_usecs_to_ticks(g_ble_ll_sched_data.sch_ticks_per_period);
adv_rxend = os_cputime_get32();
if (ble_hdr->rxinfo.channel >= BLE_PHY_NUM_DATA_CHANS) {
/*
* We received packet on advertising channel which means this is a legacy
* PDU on 1 Mbps - we do as described above.
*/
earliest_start = adv_rxend + 57;
} else {
/*
* The calculations are similar as above.
*
* We received packet on data channel which means this is AUX_ADV_IND
* received on secondary adv channel. We can schedule first packet at
* the earliest after "T_IFS + AUX_CONNECT_REQ + transmitWindowDelay".
* AUX_CONNECT_REQ and transmitWindowDelay times vary depending on which
* PHY we received on.
*
*/
if (ble_hdr->rxinfo.phy == BLE_PHY_1M) {
// 150 + 352 + 2500 = 3002us = 98.37 ticks
earliest_start = adv_rxend + 98;
} else if (ble_hdr->rxinfo.phy == BLE_PHY_2M) {
// 150 + 180 + 2500 = 2830us = 92.73 ticks
earliest_start = adv_rxend + 93;
} else if (ble_hdr->rxinfo.phy == BLE_PHY_CODED) {
// 150 + 2896 + 3750 = 6796us = 222.69 ticks
earliest_start = adv_rxend + 223;
} else {
assert(0);
}
}
itvl_t = connsm->conn_itvl_ticks;
/* We have to find a place for this schedule */
OS_ENTER_CRITICAL(sr);
/*
* Are there any allocated periods? If not, set epoch start to earliest
* time
*/
if (g_ble_ll_sched_data.sch_num_occ_periods == 0) {
g_ble_ll_sched_data.sch_epoch_start = earliest_start;
cp = 0;
} else {
/*
* Earliest start must occur on period boundary.
* (tse = ticks since epoch)
*/
tpp = g_ble_ll_sched_data.sch_ticks_per_period;
tse = earliest_start - g_ble_ll_sched_data.sch_epoch_start;
np = tse / tpp;
cp = np % BLE_LL_SCHED_PERIODS;
tick_in_period = tse - (np * tpp);
if (tick_in_period != 0) {
++cp;
if (cp == BLE_LL_SCHED_PERIODS) {
cp = 0;
}
earliest_start += (tpp - tick_in_period);
}
/* Now find first un-occupied period starting from cp */
for (i = 0; i < BLE_LL_SCHED_PERIODS; ++i) {
if (g_ble_ll_sched_data.sch_occ_period_mask & (1 << cp)) {
++cp;
if (cp == BLE_LL_SCHED_PERIODS) {
cp = 0;
}
earliest_start += tpp;
} else {
/* not occupied */
break;
}
}
/* Should never happen but if it does... */
if (i == BLE_LL_SCHED_PERIODS) {
OS_EXIT_CRITICAL(sr);
return rc;
}
}
sch->start_time = earliest_start;
initial_start = earliest_start;
earliest_end = earliest_start + dur;
if (!ble_ll_sched_insert_if_empty(sch)) {
/* Nothing in schedule. Schedule as soon as possible */
rc = 0;
connsm->tx_win_off = MYNEWT_VAL(BLE_LL_CONN_INIT_MIN_WIN_OFFSET);
} else {
os_cputime_timer_stop(&g_ble_ll_sched_timer);
TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) {
/* Set these because overlap function needs them to be set */
sch->start_time = earliest_start;
sch->end_time = earliest_end;
/* 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;
}
/* 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;
}
}
/* Must be able to schedule within one connection interval */
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 window offsets. Each offset is 1.25 ms */
sch->enqueued = 1;
/*
* NOTE: we dont add sched offset ticks as we want to under-estimate
* the transmit window slightly since the window size is currently
* 2 when using a 32768 crystal.
*/
dur = os_cputime_ticks_to_usecs(earliest_start - initial_start);
connsm->tx_win_off = dur / BLE_LL_CONN_TX_OFF_USECS;
}
}
if (!rc) {
sch->start_time = earliest_start;
sch->end_time = earliest_end;
/*
* Since we have the transmit window to transmit in, we dont need
* to set the anchor point usecs; just transmit to the nearest tick.
*/
connsm->anchor_point = earliest_start + g_ble_ll_sched_offset_ticks;
connsm->anchor_point_usecs = 0;
connsm->ce_end_time = earliest_end;
connsm->period_occ_mask = (1 << cp);
g_ble_ll_sched_data.sch_occ_period_mask |= connsm->period_occ_mask;
++g_ble_ll_sched_data.sch_num_occ_periods;
}
/* Get head of list to restart timer */
sch = TAILQ_FIRST(&g_ble_ll_sched_q);
OS_EXIT_CRITICAL(sr);
os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time);
return rc;
}
#else
int
ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm,
struct ble_mbuf_hdr *ble_hdr, uint8_t pyld_len)
@@ -474,6 +710,7 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm,
return rc;
}
#endif
/**
* Schedules a slave connection for the first time.
@@ -1204,5 +1441,14 @@ ble_ll_sched_init(void)
/* Initialize cputimer for the scheduler */
os_cputime_timer_init(&g_ble_ll_sched_timer, ble_ll_sched_run, NULL);
#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING)
memset(&g_ble_ll_sched_data, 0, sizeof(struct ble_ll_sched_obj));
g_ble_ll_sched_data.sch_ticks_per_period =
os_cputime_usecs_to_ticks(MYNEWT_VAL(BLE_LL_USECS_PER_PERIOD));
g_ble_ll_sched_data.sch_ticks_per_epoch = BLE_LL_SCHED_PERIODS *
g_ble_ll_sched_data.sch_ticks_per_period;
#endif
return 0;
}
+21
View File
@@ -148,6 +148,27 @@ syscfg.defs:
ensure interoperability with such devices set this value to 2 (or more).
value: '0'
# Strict scheduling
BLE_LL_STRICT_CONN_SCHEDULING:
description: >
Forces the scheduler on a central to schedule connections in fixed
time intervals called periods. If set to 0, the scheduler is not forced
to do this. If set to 1, the scheduler will only schedule connections at
period boundaries. See comments in ble_ll_sched.h for more details.
value: '1'
BLE_LL_ADD_STRICT_SCHED_PERIODS:
description: >
The number of additional periods that will be allocated for strict
scheduling. The total # of periods allocated for strict scheduling
will be equal to the number of connections plus this number.
value: '0'
BLE_LL_USECS_PER_PERIOD:
description: >
The number of usecs per period.
value: '3250'
# The number of random bytes to store
BLE_LL_RNG_BUFSIZE:
description: >