nimble/monitor: Add reporting of dropped packets

When using RTT in buffered mode it's possible that we drop some packets
due to not enough space in RTT buffer. In this case btsnoop format has
headers to include this information so it can be decoded by btmon.

X-Original-Commit: 22e68eb67da87cb9b807e8d99dfdd6d6835b5721
This commit is contained in:
Andrzej Kaczmarek
2017-09-04 09:04:53 +02:00
parent 2b2fbbb630
commit f3d2de2bc4
2 changed files with 144 additions and 29 deletions
+129 -27
View File
@@ -35,6 +35,7 @@
#if MYNEWT_VAL(BLE_MONITOR_RTT)
#include "rtt/SEGGER_RTT.h"
#endif
#include "ble_hs_priv.h"
#include "ble_monitor_priv.h"
struct os_mutex lock;
@@ -53,6 +54,12 @@ static int rtt_index;
#if MYNEWT_VAL(BLE_MONITOR_RTT_BUFFERED)
static uint8_t rtt_pktbuf[MYNEWT_VAL(BLE_MONITOR_RTT_BUFFER_SIZE)];
static size_t rtt_pktbuf_pos;
static struct {
bool dropped;
struct os_callout tmo;
struct ble_monitor_drops_hdr drops_hdr;
} rtt_drops;
#endif
#endif
@@ -117,12 +124,60 @@ monitor_write(const void *buf, size_t len)
#endif
#if MYNEWT_VAL(BLE_MONITOR_RTT)
#if MYNEWT_VAL(BLE_MONITOR_RTT_BUFFERED)
static void
update_drop_counters(struct ble_monitor_hdr *failed_hdr)
{
uint8_t *cnt;
rtt_drops.dropped = true;
switch (failed_hdr->opcode) {
case BLE_MONITOR_OPCODE_COMMAND_PKT:
cnt = &rtt_drops.drops_hdr.cmd;
break;
case BLE_MONITOR_OPCODE_EVENT_PKT:
cnt = &rtt_drops.drops_hdr.evt;
break;
case BLE_MONITOR_OPCODE_ACL_TX_PKT:
cnt = &rtt_drops.drops_hdr.acl_tx;
break;
case BLE_MONITOR_OPCODE_ACL_RX_PKT:
cnt = &rtt_drops.drops_hdr.acl_rx;
break;
default:
cnt = &rtt_drops.drops_hdr.other;
break;
}
if (*cnt < UINT8_MAX) {
(*cnt)++;
os_callout_reset(&rtt_drops.tmo, OS_TICKS_PER_SEC);
}
}
static void
reset_drop_counters(void)
{
rtt_drops.dropped = false;
rtt_drops.drops_hdr.cmd = 0;
rtt_drops.drops_hdr.evt = 0;
rtt_drops.drops_hdr.acl_tx = 0;
rtt_drops.drops_hdr.acl_rx = 0;
rtt_drops.drops_hdr.other = 0;
os_callout_stop(&rtt_drops.tmo);
}
#endif
static void
monitor_write(const void *buf, size_t len)
{
#if MYNEWT_VAL(BLE_MONITOR_RTT_BUFFERED)
struct ble_monitor_hdr *hdr = (struct ble_monitor_hdr *) rtt_pktbuf;
bool discard;
unsigned ret = 0;
/* We will discard any packet which exceeds length of intermediate buffer */
discard = rtt_pktbuf_pos + len > sizeof(rtt_pktbuf);
@@ -136,9 +191,14 @@ monitor_write(const void *buf, size_t len)
return;
}
// TODO: count dropped packets
if (!discard) {
SEGGER_RTT_WriteNoLock(rtt_index, rtt_pktbuf, rtt_pktbuf_pos);
ret = SEGGER_RTT_WriteNoLock(rtt_index, rtt_pktbuf, rtt_pktbuf_pos);
}
if (ret > 0) {
reset_drop_counters();
} else {
update_drop_counters(hdr);
}
rtt_pktbuf_pos = 0;
@@ -148,6 +208,49 @@ monitor_write(const void *buf, size_t len)
}
#endif
static void
monitor_write_header(uint16_t opcode, uint16_t len)
{
struct ble_monitor_hdr hdr;
struct ble_monitor_ts_hdr ts_hdr;
uint8_t hdr_len;
int64_t ts;
hdr_len = sizeof(ts_hdr);
#if MYNEWT_VAL(BLE_MONITOR_RTT) && MYNEWT_VAL(BLE_MONITOR_RTT_BUFFERED)
if (rtt_drops.dropped) {
hdr_len += sizeof(rtt_drops.drops_hdr);
}
#endif
hdr.data_len = htole16(4 + hdr_len + len);
hdr.hdr_len = hdr_len;
hdr.opcode = htole16(opcode);
hdr.flags = 0;
/* Use uptime for timestamp */
ts = os_get_uptime_usec();
/*
* btsnoop specification states that fields of extended header must be
* sorted in increasing order so we will send drops (if any) headers before
* timestamp header.
*/
monitor_write(&hdr, sizeof(hdr));
#if MYNEWT_VAL(BLE_MONITOR_RTT) && MYNEWT_VAL(BLE_MONITOR_RTT_BUFFERED)
if (rtt_drops.dropped) {
monitor_write(&rtt_drops.drops_hdr, sizeof(rtt_drops.drops_hdr));
}
#endif
ts_hdr.type = BLE_MONITOR_EXTHDR_TS32;
ts_hdr.ts32 = htole32(ts / 100);
monitor_write(&ts_hdr, sizeof(ts_hdr));
}
static size_t
btmon_write(FILE *instance, const char *bp, size_t n)
{
@@ -162,23 +265,23 @@ static FILE *btmon = (FILE *) &(struct File) {
},
};
#if MYNEWT_VAL(BLE_MONITOR_RTT) && MYNEWT_VAL(BLE_MONITOR_RTT_BUFFERED)
static void
encode_monitor_hdr(struct ble_monitor_hdr *hdr, uint16_t opcode, uint16_t len)
drops_tmp_cb(struct os_event *ev)
{
int64_t ts;
os_mutex_pend(&lock, OS_TIMEOUT_NEVER);
hdr->hdr_len = sizeof(hdr->type) + sizeof(hdr->ts32);
hdr->data_len = htole16(4 + hdr->hdr_len + len);
hdr->opcode = htole16(opcode);
hdr->flags = 0;
/*
* There's no "nop" in btsnoop protocol so we just send empty system note
* to indicate drops.
*/
/* Use uptime for timestamp */
ts = os_get_uptime_usec();
monitor_write_header(BLE_MONITOR_OPCODE_SYSTEM_NOTE, 1);
monitor_write("", 1);
/* Extended header */
hdr->type = BLE_MONITOR_EXTHDR_TS32;
hdr->ts32 = htole32(ts / 100);
os_mutex_release(&lock);
}
#endif
int
ble_monitor_init(void)
@@ -204,6 +307,15 @@ ble_monitor_init(void)
#if MYNEWT_VAL(BLE_MONITOR_RTT)
#if MYNEWT_VAL(BLE_MONITOR_RTT_BUFFERED)
os_callout_init(&rtt_drops.tmo, ble_hs_evq_get(), drops_tmp_cb, NULL);
/* Initialize types in header (we won't touch them later) */
rtt_drops.drops_hdr.type_cmd = BLE_MONITOR_EXTHDR_COMMAND_DROPS;
rtt_drops.drops_hdr.type_evt = BLE_MONITOR_EXTHDR_EVENT_DROPS;
rtt_drops.drops_hdr.type_acl_tx = BLE_MONITOR_EXTHDR_ACL_TX_DROPS;
rtt_drops.drops_hdr.type_acl_rx = BLE_MONITOR_EXTHDR_ACL_RX_DROPS;
rtt_drops.drops_hdr.type_other = BLE_MONITOR_EXTHDR_OTHER_DROPS;
rtt_index = SEGGER_RTT_AllocUpBuffer(MYNEWT_VAL(BLE_MONITOR_RTT_BUFFER_NAME),
rtt_buf, sizeof(rtt_buf),
SEGGER_RTT_MODE_NO_BLOCK_SKIP);
@@ -226,13 +338,9 @@ ble_monitor_init(void)
int
ble_monitor_send(uint16_t opcode, const void *data, size_t len)
{
struct ble_monitor_hdr hdr;
encode_monitor_hdr(&hdr, opcode, len);
os_mutex_pend(&lock, OS_TIMEOUT_NEVER);
monitor_write(&hdr, sizeof(hdr));
monitor_write_header(opcode, len);
monitor_write(data, len);
os_mutex_release(&lock);
@@ -244,7 +352,6 @@ int
ble_monitor_send_om(uint16_t opcode, const struct os_mbuf *om)
{
const struct os_mbuf *om_tmp;
struct ble_monitor_hdr hdr;
uint16_t length = 0;
om_tmp = om;
@@ -253,11 +360,9 @@ ble_monitor_send_om(uint16_t opcode, const struct os_mbuf *om)
om_tmp = SLIST_NEXT(om_tmp, om_next);
}
encode_monitor_hdr(&hdr, opcode, length);
os_mutex_pend(&lock, OS_TIMEOUT_NEVER);
monitor_write(&hdr, sizeof(hdr));
monitor_write_header(opcode, length);
while (om) {
monitor_write(om->om_data, om->om_len);
@@ -289,7 +394,6 @@ int
ble_monitor_log(int level, const char *fmt, ...)
{
static const char id[] = "nimble";
struct ble_monitor_hdr hdr;
struct ble_monitor_user_logging ulog;
va_list va;
int len;
@@ -318,12 +422,10 @@ ble_monitor_log(int level, const char *fmt, ...)
ulog.ident_len = sizeof(id);
encode_monitor_hdr(&hdr, BLE_MONITOR_OPCODE_USER_LOGGING,
sizeof(ulog) + sizeof(id) + len + 1);
os_mutex_pend(&lock, OS_TIMEOUT_NEVER);
monitor_write(&hdr, sizeof(hdr));
monitor_write_header(BLE_MONITOR_OPCODE_USER_LOGGING,
sizeof(ulog) + sizeof(id) + len + 1);
monitor_write(&ulog, sizeof(ulog));
monitor_write(id, sizeof(id));
+15 -2
View File
@@ -38,7 +38,6 @@ extern "C" {
#define BLE_MONITOR_OPCODE_VENDOR_DIAG 11
#define BLE_MONITOR_OPCODE_SYSTEM_NOTE 12
#define BLE_MONITOR_OPCODE_USER_LOGGING 13
#define BLE_MONITOR_OPCODE_NOP 255
#define BLE_MONITOR_EXTHDR_COMMAND_DROPS 1
#define BLE_MONITOR_EXTHDR_EVENT_DROPS 2
@@ -54,8 +53,22 @@ struct ble_monitor_hdr {
uint16_t opcode;
uint8_t flags;
uint8_t hdr_len;
} __attribute__((packed));
/* Extended header (timestamp always present) */
struct ble_monitor_drops_hdr {
uint8_t type_cmd;
uint8_t cmd;
uint8_t type_evt;
uint8_t evt;
uint8_t type_acl_tx;
uint8_t acl_tx;
uint8_t type_acl_rx;
uint8_t acl_rx;
uint8_t type_other;
uint8_t other;
} __attribute__((packed));
struct ble_monitor_ts_hdr {
uint8_t type;
uint32_t ts32;
} __attribute__((packed));