1*042d53a7SEvalZero /*
2*042d53a7SEvalZero * Licensed to the Apache Software Foundation (ASF) under one
3*042d53a7SEvalZero * or more contributor license agreements. See the NOTICE file
4*042d53a7SEvalZero * distributed with this work for additional information
5*042d53a7SEvalZero * regarding copyright ownership. The ASF licenses this file
6*042d53a7SEvalZero * to you under the Apache License, Version 2.0 (the
7*042d53a7SEvalZero * "License"); you may not use this file except in compliance
8*042d53a7SEvalZero * with the License. You may obtain a copy of the License at
9*042d53a7SEvalZero *
10*042d53a7SEvalZero * http://www.apache.org/licenses/LICENSE-2.0
11*042d53a7SEvalZero *
12*042d53a7SEvalZero * Unless required by applicable law or agreed to in writing,
13*042d53a7SEvalZero * software distributed under the License is distributed on an
14*042d53a7SEvalZero * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15*042d53a7SEvalZero * KIND, either express or implied. See the License for the
16*042d53a7SEvalZero * specific language governing permissions and limitations
17*042d53a7SEvalZero * under the License.
18*042d53a7SEvalZero */
19*042d53a7SEvalZero
20*042d53a7SEvalZero #include "host/ble_monitor.h"
21*042d53a7SEvalZero
22*042d53a7SEvalZero #if BLE_MONITOR
23*042d53a7SEvalZero
24*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MONITOR_UART) && MYNEWT_VAL(BLE_MONITOR_RTT)
25*042d53a7SEvalZero #error "Cannot enable monitor over UART and RTT at the same time!"
26*042d53a7SEvalZero #endif
27*042d53a7SEvalZero
28*042d53a7SEvalZero #include <stdarg.h>
29*042d53a7SEvalZero #include <stdio.h>
30*042d53a7SEvalZero #include <inttypes.h>
31*042d53a7SEvalZero #include "os/os.h"
32*042d53a7SEvalZero #include "log/log.h"
33*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MONITOR_UART)
34*042d53a7SEvalZero #include "uart/uart.h"
35*042d53a7SEvalZero #endif
36*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MONITOR_RTT)
37*042d53a7SEvalZero #include "rtt/SEGGER_RTT.h"
38*042d53a7SEvalZero #endif
39*042d53a7SEvalZero #include "ble_hs_priv.h"
40*042d53a7SEvalZero #include "ble_monitor_priv.h"
41*042d53a7SEvalZero
42*042d53a7SEvalZero struct ble_npl_mutex lock;
43*042d53a7SEvalZero
44*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MONITOR_UART)
45*042d53a7SEvalZero struct uart_dev *uart;
46*042d53a7SEvalZero
47*042d53a7SEvalZero static uint8_t tx_ringbuf[MYNEWT_VAL(BLE_MONITOR_UART_BUFFER_SIZE)];
48*042d53a7SEvalZero static uint8_t tx_ringbuf_head;
49*042d53a7SEvalZero static uint8_t tx_ringbuf_tail;
50*042d53a7SEvalZero #endif
51*042d53a7SEvalZero
52*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MONITOR_RTT)
53*042d53a7SEvalZero static uint8_t rtt_buf[MYNEWT_VAL(BLE_MONITOR_RTT_BUFFER_SIZE)];
54*042d53a7SEvalZero static int rtt_index;
55*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MONITOR_RTT_BUFFERED)
56*042d53a7SEvalZero static uint8_t rtt_pktbuf[MYNEWT_VAL(BLE_MONITOR_RTT_BUFFER_SIZE)];
57*042d53a7SEvalZero static size_t rtt_pktbuf_pos;
58*042d53a7SEvalZero static struct {
59*042d53a7SEvalZero bool dropped;
60*042d53a7SEvalZero struct ble_npl_callout tmo;
61*042d53a7SEvalZero struct ble_monitor_drops_hdr drops_hdr;
62*042d53a7SEvalZero } rtt_drops;
63*042d53a7SEvalZero
64*042d53a7SEvalZero #endif
65*042d53a7SEvalZero #endif
66*042d53a7SEvalZero
67*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MONITOR_UART)
68*042d53a7SEvalZero static inline int
inc_and_wrap(int i,int max)69*042d53a7SEvalZero inc_and_wrap(int i, int max)
70*042d53a7SEvalZero {
71*042d53a7SEvalZero return (i + 1) & (max - 1);
72*042d53a7SEvalZero }
73*042d53a7SEvalZero
74*042d53a7SEvalZero static int
monitor_uart_rx_discard(void * arg,uint8_t ch)75*042d53a7SEvalZero monitor_uart_rx_discard(void *arg, uint8_t ch)
76*042d53a7SEvalZero {
77*042d53a7SEvalZero return 0;
78*042d53a7SEvalZero }
79*042d53a7SEvalZero
80*042d53a7SEvalZero static int
monitor_uart_tx_char(void * arg)81*042d53a7SEvalZero monitor_uart_tx_char(void *arg)
82*042d53a7SEvalZero {
83*042d53a7SEvalZero uint8_t ch;
84*042d53a7SEvalZero
85*042d53a7SEvalZero /* No more data */
86*042d53a7SEvalZero if (tx_ringbuf_head == tx_ringbuf_tail) {
87*042d53a7SEvalZero return -1;
88*042d53a7SEvalZero }
89*042d53a7SEvalZero
90*042d53a7SEvalZero ch = tx_ringbuf[tx_ringbuf_tail];
91*042d53a7SEvalZero tx_ringbuf_tail = inc_and_wrap(tx_ringbuf_tail, sizeof(tx_ringbuf));
92*042d53a7SEvalZero
93*042d53a7SEvalZero return ch;
94*042d53a7SEvalZero }
95*042d53a7SEvalZero
96*042d53a7SEvalZero static void
monitor_uart_queue_char(uint8_t ch)97*042d53a7SEvalZero monitor_uart_queue_char(uint8_t ch)
98*042d53a7SEvalZero {
99*042d53a7SEvalZero int sr;
100*042d53a7SEvalZero
101*042d53a7SEvalZero OS_ENTER_CRITICAL(sr);
102*042d53a7SEvalZero
103*042d53a7SEvalZero /* We need to try flush some data from ringbuffer if full */
104*042d53a7SEvalZero while (inc_and_wrap(tx_ringbuf_head, sizeof(tx_ringbuf)) ==
105*042d53a7SEvalZero tx_ringbuf_tail) {
106*042d53a7SEvalZero uart_start_tx(uart);
107*042d53a7SEvalZero OS_EXIT_CRITICAL(sr);
108*042d53a7SEvalZero if (os_started()) {
109*042d53a7SEvalZero os_time_delay(1);
110*042d53a7SEvalZero }
111*042d53a7SEvalZero OS_ENTER_CRITICAL(sr);
112*042d53a7SEvalZero }
113*042d53a7SEvalZero
114*042d53a7SEvalZero tx_ringbuf[tx_ringbuf_head] = ch;
115*042d53a7SEvalZero tx_ringbuf_head = inc_and_wrap(tx_ringbuf_head, sizeof(tx_ringbuf));
116*042d53a7SEvalZero
117*042d53a7SEvalZero OS_EXIT_CRITICAL(sr);
118*042d53a7SEvalZero }
119*042d53a7SEvalZero
120*042d53a7SEvalZero static void
monitor_write(const void * buf,size_t len)121*042d53a7SEvalZero monitor_write(const void *buf, size_t len)
122*042d53a7SEvalZero {
123*042d53a7SEvalZero const uint8_t *ch = buf;
124*042d53a7SEvalZero
125*042d53a7SEvalZero while (len--) {
126*042d53a7SEvalZero monitor_uart_queue_char(*ch++);
127*042d53a7SEvalZero }
128*042d53a7SEvalZero
129*042d53a7SEvalZero uart_start_tx(uart);
130*042d53a7SEvalZero }
131*042d53a7SEvalZero #endif
132*042d53a7SEvalZero
133*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MONITOR_RTT)
134*042d53a7SEvalZero
135*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MONITOR_RTT_BUFFERED)
136*042d53a7SEvalZero static void
update_drop_counters(struct ble_monitor_hdr * failed_hdr)137*042d53a7SEvalZero update_drop_counters(struct ble_monitor_hdr *failed_hdr)
138*042d53a7SEvalZero {
139*042d53a7SEvalZero uint8_t *cnt;
140*042d53a7SEvalZero
141*042d53a7SEvalZero rtt_drops.dropped = true;
142*042d53a7SEvalZero
143*042d53a7SEvalZero switch (failed_hdr->opcode) {
144*042d53a7SEvalZero case BLE_MONITOR_OPCODE_COMMAND_PKT:
145*042d53a7SEvalZero cnt = &rtt_drops.drops_hdr.cmd;
146*042d53a7SEvalZero break;
147*042d53a7SEvalZero case BLE_MONITOR_OPCODE_EVENT_PKT:
148*042d53a7SEvalZero cnt = &rtt_drops.drops_hdr.evt;
149*042d53a7SEvalZero break;
150*042d53a7SEvalZero case BLE_MONITOR_OPCODE_ACL_TX_PKT:
151*042d53a7SEvalZero cnt = &rtt_drops.drops_hdr.acl_tx;
152*042d53a7SEvalZero break;
153*042d53a7SEvalZero case BLE_MONITOR_OPCODE_ACL_RX_PKT:
154*042d53a7SEvalZero cnt = &rtt_drops.drops_hdr.acl_rx;
155*042d53a7SEvalZero break;
156*042d53a7SEvalZero default:
157*042d53a7SEvalZero cnt = &rtt_drops.drops_hdr.other;
158*042d53a7SEvalZero break;
159*042d53a7SEvalZero }
160*042d53a7SEvalZero
161*042d53a7SEvalZero if (*cnt < UINT8_MAX) {
162*042d53a7SEvalZero (*cnt)++;
163*042d53a7SEvalZero ble_npl_callout_reset(&rtt_drops.tmo, OS_TICKS_PER_SEC);
164*042d53a7SEvalZero }
165*042d53a7SEvalZero }
166*042d53a7SEvalZero
167*042d53a7SEvalZero static void
reset_drop_counters(void)168*042d53a7SEvalZero reset_drop_counters(void)
169*042d53a7SEvalZero {
170*042d53a7SEvalZero rtt_drops.dropped = false;
171*042d53a7SEvalZero rtt_drops.drops_hdr.cmd = 0;
172*042d53a7SEvalZero rtt_drops.drops_hdr.evt = 0;
173*042d53a7SEvalZero rtt_drops.drops_hdr.acl_tx = 0;
174*042d53a7SEvalZero rtt_drops.drops_hdr.acl_rx = 0;
175*042d53a7SEvalZero rtt_drops.drops_hdr.other = 0;
176*042d53a7SEvalZero
177*042d53a7SEvalZero ble_npl_callout_stop(&rtt_drops.tmo);
178*042d53a7SEvalZero }
179*042d53a7SEvalZero #endif
180*042d53a7SEvalZero
181*042d53a7SEvalZero static void
monitor_write(const void * buf,size_t len)182*042d53a7SEvalZero monitor_write(const void *buf, size_t len)
183*042d53a7SEvalZero {
184*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MONITOR_RTT_BUFFERED)
185*042d53a7SEvalZero struct ble_monitor_hdr *hdr = (struct ble_monitor_hdr *) rtt_pktbuf;
186*042d53a7SEvalZero bool discard;
187*042d53a7SEvalZero unsigned ret = 0;
188*042d53a7SEvalZero
189*042d53a7SEvalZero /* We will discard any packet which exceeds length of intermediate buffer */
190*042d53a7SEvalZero discard = rtt_pktbuf_pos + len > sizeof(rtt_pktbuf);
191*042d53a7SEvalZero
192*042d53a7SEvalZero if (!discard) {
193*042d53a7SEvalZero memcpy(rtt_pktbuf + rtt_pktbuf_pos, buf, len);
194*042d53a7SEvalZero }
195*042d53a7SEvalZero
196*042d53a7SEvalZero rtt_pktbuf_pos += len;
197*042d53a7SEvalZero if (rtt_pktbuf_pos < sizeof(hdr->data_len) + hdr->data_len) {
198*042d53a7SEvalZero return;
199*042d53a7SEvalZero }
200*042d53a7SEvalZero
201*042d53a7SEvalZero if (!discard) {
202*042d53a7SEvalZero ret = SEGGER_RTT_WriteNoLock(rtt_index, rtt_pktbuf, rtt_pktbuf_pos);
203*042d53a7SEvalZero }
204*042d53a7SEvalZero
205*042d53a7SEvalZero if (ret > 0) {
206*042d53a7SEvalZero reset_drop_counters();
207*042d53a7SEvalZero } else {
208*042d53a7SEvalZero update_drop_counters(hdr);
209*042d53a7SEvalZero }
210*042d53a7SEvalZero
211*042d53a7SEvalZero rtt_pktbuf_pos = 0;
212*042d53a7SEvalZero #else
213*042d53a7SEvalZero SEGGER_RTT_WriteNoLock(rtt_index, buf, len);
214*042d53a7SEvalZero #endif
215*042d53a7SEvalZero }
216*042d53a7SEvalZero #endif
217*042d53a7SEvalZero
218*042d53a7SEvalZero static void
monitor_write_header(uint16_t opcode,uint16_t len)219*042d53a7SEvalZero monitor_write_header(uint16_t opcode, uint16_t len)
220*042d53a7SEvalZero {
221*042d53a7SEvalZero struct ble_monitor_hdr hdr;
222*042d53a7SEvalZero struct ble_monitor_ts_hdr ts_hdr;
223*042d53a7SEvalZero uint8_t hdr_len;
224*042d53a7SEvalZero int64_t ts;
225*042d53a7SEvalZero
226*042d53a7SEvalZero hdr_len = sizeof(ts_hdr);
227*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MONITOR_RTT) && MYNEWT_VAL(BLE_MONITOR_RTT_BUFFERED)
228*042d53a7SEvalZero if (rtt_drops.dropped) {
229*042d53a7SEvalZero hdr_len += sizeof(rtt_drops.drops_hdr);
230*042d53a7SEvalZero }
231*042d53a7SEvalZero #endif
232*042d53a7SEvalZero
233*042d53a7SEvalZero hdr.data_len = htole16(4 + hdr_len + len);
234*042d53a7SEvalZero hdr.hdr_len = hdr_len;
235*042d53a7SEvalZero hdr.opcode = htole16(opcode);
236*042d53a7SEvalZero hdr.flags = 0;
237*042d53a7SEvalZero
238*042d53a7SEvalZero /* Use uptime for timestamp */
239*042d53a7SEvalZero ts = os_get_uptime_usec();
240*042d53a7SEvalZero
241*042d53a7SEvalZero /*
242*042d53a7SEvalZero * btsnoop specification states that fields of extended header must be
243*042d53a7SEvalZero * sorted in increasing order so we will send drops (if any) headers before
244*042d53a7SEvalZero * timestamp header.
245*042d53a7SEvalZero */
246*042d53a7SEvalZero
247*042d53a7SEvalZero monitor_write(&hdr, sizeof(hdr));
248*042d53a7SEvalZero
249*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MONITOR_RTT) && MYNEWT_VAL(BLE_MONITOR_RTT_BUFFERED)
250*042d53a7SEvalZero if (rtt_drops.dropped) {
251*042d53a7SEvalZero monitor_write(&rtt_drops.drops_hdr, sizeof(rtt_drops.drops_hdr));
252*042d53a7SEvalZero }
253*042d53a7SEvalZero #endif
254*042d53a7SEvalZero
255*042d53a7SEvalZero ts_hdr.type = BLE_MONITOR_EXTHDR_TS32;
256*042d53a7SEvalZero ts_hdr.ts32 = htole32(ts / 100);
257*042d53a7SEvalZero
258*042d53a7SEvalZero monitor_write(&ts_hdr, sizeof(ts_hdr));
259*042d53a7SEvalZero }
260*042d53a7SEvalZero
261*042d53a7SEvalZero static size_t
btmon_write(FILE * instance,const char * bp,size_t n)262*042d53a7SEvalZero btmon_write(FILE *instance, const char *bp, size_t n)
263*042d53a7SEvalZero {
264*042d53a7SEvalZero monitor_write(bp, n);
265*042d53a7SEvalZero
266*042d53a7SEvalZero return n;
267*042d53a7SEvalZero }
268*042d53a7SEvalZero
269*042d53a7SEvalZero static FILE *btmon = (FILE *) &(struct File) {
270*042d53a7SEvalZero .vmt = &(struct File_methods) {
271*042d53a7SEvalZero .write = btmon_write,
272*042d53a7SEvalZero },
273*042d53a7SEvalZero };
274*042d53a7SEvalZero
275*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MONITOR_RTT) && MYNEWT_VAL(BLE_MONITOR_RTT_BUFFERED)
276*042d53a7SEvalZero static void
drops_tmp_cb(struct ble_npl_event * ev)277*042d53a7SEvalZero drops_tmp_cb(struct ble_npl_event *ev)
278*042d53a7SEvalZero {
279*042d53a7SEvalZero ble_npl_mutex_pend(&lock, OS_TIMEOUT_NEVER);
280*042d53a7SEvalZero
281*042d53a7SEvalZero /*
282*042d53a7SEvalZero * There's no "nop" in btsnoop protocol so we just send empty system note
283*042d53a7SEvalZero * to indicate drops.
284*042d53a7SEvalZero */
285*042d53a7SEvalZero
286*042d53a7SEvalZero monitor_write_header(BLE_MONITOR_OPCODE_SYSTEM_NOTE, 1);
287*042d53a7SEvalZero monitor_write("", 1);
288*042d53a7SEvalZero
289*042d53a7SEvalZero ble_npl_mutex_release(&lock);
290*042d53a7SEvalZero }
291*042d53a7SEvalZero #endif
292*042d53a7SEvalZero
293*042d53a7SEvalZero int
ble_monitor_init(void)294*042d53a7SEvalZero ble_monitor_init(void)
295*042d53a7SEvalZero {
296*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MONITOR_UART)
297*042d53a7SEvalZero struct uart_conf uc = {
298*042d53a7SEvalZero .uc_speed = MYNEWT_VAL(BLE_MONITOR_UART_BAUDRATE),
299*042d53a7SEvalZero .uc_databits = 8,
300*042d53a7SEvalZero .uc_stopbits = 1,
301*042d53a7SEvalZero .uc_parity = UART_PARITY_NONE,
302*042d53a7SEvalZero .uc_flow_ctl = UART_FLOW_CTL_NONE,
303*042d53a7SEvalZero .uc_tx_char = monitor_uart_tx_char,
304*042d53a7SEvalZero .uc_rx_char = monitor_uart_rx_discard,
305*042d53a7SEvalZero .uc_cb_arg = NULL,
306*042d53a7SEvalZero };
307*042d53a7SEvalZero
308*042d53a7SEvalZero uart = (struct uart_dev *)os_dev_open(MYNEWT_VAL(BLE_MONITOR_UART_DEV),
309*042d53a7SEvalZero OS_TIMEOUT_NEVER, &uc);
310*042d53a7SEvalZero if (!uart) {
311*042d53a7SEvalZero return -1;
312*042d53a7SEvalZero }
313*042d53a7SEvalZero #endif
314*042d53a7SEvalZero
315*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MONITOR_RTT)
316*042d53a7SEvalZero #if MYNEWT_VAL(BLE_MONITOR_RTT_BUFFERED)
317*042d53a7SEvalZero ble_npl_callout_init(&rtt_drops.tmo, ble_hs_evq_get(), drops_tmp_cb, NULL);
318*042d53a7SEvalZero
319*042d53a7SEvalZero /* Initialize types in header (we won't touch them later) */
320*042d53a7SEvalZero rtt_drops.drops_hdr.type_cmd = BLE_MONITOR_EXTHDR_COMMAND_DROPS;
321*042d53a7SEvalZero rtt_drops.drops_hdr.type_evt = BLE_MONITOR_EXTHDR_EVENT_DROPS;
322*042d53a7SEvalZero rtt_drops.drops_hdr.type_acl_tx = BLE_MONITOR_EXTHDR_ACL_TX_DROPS;
323*042d53a7SEvalZero rtt_drops.drops_hdr.type_acl_rx = BLE_MONITOR_EXTHDR_ACL_RX_DROPS;
324*042d53a7SEvalZero rtt_drops.drops_hdr.type_other = BLE_MONITOR_EXTHDR_OTHER_DROPS;
325*042d53a7SEvalZero
326*042d53a7SEvalZero rtt_index = SEGGER_RTT_AllocUpBuffer(MYNEWT_VAL(BLE_MONITOR_RTT_BUFFER_NAME),
327*042d53a7SEvalZero rtt_buf, sizeof(rtt_buf),
328*042d53a7SEvalZero SEGGER_RTT_MODE_NO_BLOCK_SKIP);
329*042d53a7SEvalZero #else
330*042d53a7SEvalZero rtt_index = SEGGER_RTT_AllocUpBuffer(MYNEWT_VAL(BLE_MONITOR_RTT_BUFFER_NAME),
331*042d53a7SEvalZero rtt_buf, sizeof(rtt_buf),
332*042d53a7SEvalZero SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL);
333*042d53a7SEvalZero #endif
334*042d53a7SEvalZero
335*042d53a7SEvalZero if (rtt_index < 0) {
336*042d53a7SEvalZero return -1;
337*042d53a7SEvalZero }
338*042d53a7SEvalZero #endif
339*042d53a7SEvalZero
340*042d53a7SEvalZero ble_npl_mutex_init(&lock);
341*042d53a7SEvalZero
342*042d53a7SEvalZero return 0;
343*042d53a7SEvalZero }
344*042d53a7SEvalZero
345*042d53a7SEvalZero int
ble_monitor_send(uint16_t opcode,const void * data,size_t len)346*042d53a7SEvalZero ble_monitor_send(uint16_t opcode, const void *data, size_t len)
347*042d53a7SEvalZero {
348*042d53a7SEvalZero ble_npl_mutex_pend(&lock, OS_TIMEOUT_NEVER);
349*042d53a7SEvalZero
350*042d53a7SEvalZero monitor_write_header(opcode, len);
351*042d53a7SEvalZero monitor_write(data, len);
352*042d53a7SEvalZero
353*042d53a7SEvalZero ble_npl_mutex_release(&lock);
354*042d53a7SEvalZero
355*042d53a7SEvalZero return 0;
356*042d53a7SEvalZero }
357*042d53a7SEvalZero
358*042d53a7SEvalZero int
ble_monitor_send_om(uint16_t opcode,const struct os_mbuf * om)359*042d53a7SEvalZero ble_monitor_send_om(uint16_t opcode, const struct os_mbuf *om)
360*042d53a7SEvalZero {
361*042d53a7SEvalZero const struct os_mbuf *om_tmp;
362*042d53a7SEvalZero uint16_t length = 0;
363*042d53a7SEvalZero
364*042d53a7SEvalZero om_tmp = om;
365*042d53a7SEvalZero while (om_tmp) {
366*042d53a7SEvalZero length += om_tmp->om_len;
367*042d53a7SEvalZero om_tmp = SLIST_NEXT(om_tmp, om_next);
368*042d53a7SEvalZero }
369*042d53a7SEvalZero
370*042d53a7SEvalZero ble_npl_mutex_pend(&lock, OS_TIMEOUT_NEVER);
371*042d53a7SEvalZero
372*042d53a7SEvalZero monitor_write_header(opcode, length);
373*042d53a7SEvalZero
374*042d53a7SEvalZero while (om) {
375*042d53a7SEvalZero monitor_write(om->om_data, om->om_len);
376*042d53a7SEvalZero om = SLIST_NEXT(om, om_next);
377*042d53a7SEvalZero }
378*042d53a7SEvalZero
379*042d53a7SEvalZero ble_npl_mutex_release(&lock);
380*042d53a7SEvalZero
381*042d53a7SEvalZero return 0;
382*042d53a7SEvalZero }
383*042d53a7SEvalZero
384*042d53a7SEvalZero int
ble_monitor_new_index(uint8_t bus,uint8_t * addr,const char * name)385*042d53a7SEvalZero ble_monitor_new_index(uint8_t bus, uint8_t *addr, const char *name)
386*042d53a7SEvalZero {
387*042d53a7SEvalZero struct ble_monitor_new_index pkt;
388*042d53a7SEvalZero
389*042d53a7SEvalZero pkt.type = 0; /* Primary controller, we don't support other */
390*042d53a7SEvalZero pkt.bus = bus;
391*042d53a7SEvalZero memcpy(pkt.bdaddr, addr, 6);
392*042d53a7SEvalZero strncpy(pkt.name, name, sizeof(pkt.name) - 1);
393*042d53a7SEvalZero pkt.name[sizeof(pkt.name) - 1] = '\0';
394*042d53a7SEvalZero
395*042d53a7SEvalZero ble_monitor_send(BLE_MONITOR_OPCODE_NEW_INDEX, &pkt, sizeof(pkt));
396*042d53a7SEvalZero
397*042d53a7SEvalZero return 0;
398*042d53a7SEvalZero }
399*042d53a7SEvalZero
400*042d53a7SEvalZero int
ble_monitor_log(int level,const char * fmt,...)401*042d53a7SEvalZero ble_monitor_log(int level, const char *fmt, ...)
402*042d53a7SEvalZero {
403*042d53a7SEvalZero static const char id[] = "nimble";
404*042d53a7SEvalZero struct ble_monitor_user_logging ulog;
405*042d53a7SEvalZero va_list va;
406*042d53a7SEvalZero int len;
407*042d53a7SEvalZero
408*042d53a7SEvalZero va_start(va, fmt);
409*042d53a7SEvalZero len = vsnprintf(NULL, 0, fmt, va);
410*042d53a7SEvalZero va_end(va);
411*042d53a7SEvalZero
412*042d53a7SEvalZero switch (level) {
413*042d53a7SEvalZero case LOG_LEVEL_ERROR:
414*042d53a7SEvalZero ulog.priority = 3;
415*042d53a7SEvalZero break;
416*042d53a7SEvalZero case LOG_LEVEL_WARN:
417*042d53a7SEvalZero ulog.priority = 4;
418*042d53a7SEvalZero break;
419*042d53a7SEvalZero case LOG_LEVEL_INFO:
420*042d53a7SEvalZero ulog.priority = 6;
421*042d53a7SEvalZero break;
422*042d53a7SEvalZero case LOG_LEVEL_DEBUG:
423*042d53a7SEvalZero ulog.priority = 7;
424*042d53a7SEvalZero break;
425*042d53a7SEvalZero default:
426*042d53a7SEvalZero ulog.priority = 8;
427*042d53a7SEvalZero break;
428*042d53a7SEvalZero }
429*042d53a7SEvalZero
430*042d53a7SEvalZero ulog.ident_len = sizeof(id);
431*042d53a7SEvalZero
432*042d53a7SEvalZero ble_npl_mutex_pend(&lock, OS_TIMEOUT_NEVER);
433*042d53a7SEvalZero
434*042d53a7SEvalZero monitor_write_header(BLE_MONITOR_OPCODE_USER_LOGGING,
435*042d53a7SEvalZero sizeof(ulog) + sizeof(id) + len + 1);
436*042d53a7SEvalZero monitor_write(&ulog, sizeof(ulog));
437*042d53a7SEvalZero monitor_write(id, sizeof(id));
438*042d53a7SEvalZero
439*042d53a7SEvalZero va_start(va, fmt);
440*042d53a7SEvalZero vfprintf(btmon, fmt, va);
441*042d53a7SEvalZero va_end(va);
442*042d53a7SEvalZero
443*042d53a7SEvalZero /* null-terminate string */
444*042d53a7SEvalZero monitor_write("", 1);
445*042d53a7SEvalZero
446*042d53a7SEvalZero ble_npl_mutex_release(&lock);
447*042d53a7SEvalZero
448*042d53a7SEvalZero return 0;
449*042d53a7SEvalZero }
450*042d53a7SEvalZero
451*042d53a7SEvalZero int
ble_monitor_out(int c)452*042d53a7SEvalZero ble_monitor_out(int c)
453*042d53a7SEvalZero {
454*042d53a7SEvalZero static char buf[MYNEWT_VAL(BLE_MONITOR_CONSOLE_BUFFER_SIZE)];
455*042d53a7SEvalZero static size_t len;
456*042d53a7SEvalZero
457*042d53a7SEvalZero if (c != '\n') {
458*042d53a7SEvalZero buf[len++] = c;
459*042d53a7SEvalZero
460*042d53a7SEvalZero if (len < sizeof(buf) - 1) {
461*042d53a7SEvalZero return c;
462*042d53a7SEvalZero }
463*042d53a7SEvalZero }
464*042d53a7SEvalZero
465*042d53a7SEvalZero buf[len++] = '\0';
466*042d53a7SEvalZero
467*042d53a7SEvalZero ble_monitor_send(BLE_MONITOR_OPCODE_SYSTEM_NOTE, buf, len);
468*042d53a7SEvalZero len = 0;
469*042d53a7SEvalZero
470*042d53a7SEvalZero return c;
471*042d53a7SEvalZero }
472*042d53a7SEvalZero
473*042d53a7SEvalZero #endif
474