xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/controller/src/ble_ll_dtm.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #include "syscfg/syscfg.h"
21 #include "sysinit/sysinit.h"
22 
23 #if MYNEWT_VAL(BLE_LL_DIRECT_TEST_MODE) == 1
24 
25 #include <assert.h>
26 #include "os/os.h"
27 #include "stats/stats.h"
28 #include "controller/ble_ll.h"
29 #include "controller/ble_phy.h"
30 #include "controller/ble_ll_sched.h"
31 #include "controller/ble_ll_xcvr.h"
32 #include "ble_ll_dtm_priv.h"
33 
34 STATS_SECT_START(ble_ll_dtm_stats)
35     STATS_SECT_ENTRY(rx_count)
36     STATS_SECT_ENTRY(tx_failed)
37     STATS_SECT_ENTRY(rx_failed)
38 STATS_SECT_END
39 STATS_SECT_DECL(ble_ll_dtm_stats) ble_ll_dtm_stats;
40 
41 STATS_NAME_START(ble_ll_dtm_stats)
42     STATS_NAME(ble_ll_dtm_stats, rx_count)
43     STATS_NAME(ble_ll_dtm_stats, tx_failed)
44     STATS_NAME(ble_ll_dtm_stats, rx_failed)
45 STATS_NAME_END(ble_phy_stats)
46 
47 struct dtm_ctx {
48     uint8_t payload_packet;
49     uint8_t itvl_rem_usec;
50     uint16_t num_of_packets;
51     uint32_t itvl_ticks;
52     int active;
53     uint8_t rf_channel;
54     uint8_t phy_mode;
55     struct os_mbuf *om;
56     struct ble_npl_event evt;
57     struct ble_ll_sched_item sch;
58 };
59 
60 static struct dtm_ctx g_ble_ll_dtm_ctx;
61 
62 static const uint8_t g_ble_ll_dtm_prbs9_data[] =
63 {
64     0xff, 0xc1, 0xfb, 0xe8, 0x4c, 0x90, 0x72, 0x8b,
65     0xe7, 0xb3, 0x51, 0x89, 0x63, 0xab, 0x23, 0x23,
66     0x02, 0x84, 0x18, 0x72, 0xaa, 0x61, 0x2f, 0x3b,
67     0x51, 0xa8, 0xe5, 0x37, 0x49, 0xfb, 0xc9, 0xca,
68     0x0c, 0x18, 0x53, 0x2c, 0xfd, 0x45, 0xe3, 0x9a,
69     0xe6, 0xf1, 0x5d, 0xb0, 0xb6, 0x1b, 0xb4, 0xbe,
70     0x2a, 0x50, 0xea, 0xe9, 0x0e, 0x9c, 0x4b, 0x5e,
71     0x57, 0x24, 0xcc, 0xa1, 0xb7, 0x59, 0xb8, 0x87,
72     0xff, 0xe0, 0x7d, 0x74, 0x26, 0x48, 0xb9, 0xc5,
73     0xf3, 0xd9, 0xa8, 0xc4, 0xb1, 0xd5, 0x91, 0x11,
74     0x01, 0x42, 0x0c, 0x39, 0xd5, 0xb0, 0x97, 0x9d,
75     0x28, 0xd4, 0xf2, 0x9b, 0xa4, 0xfd, 0x64, 0x65,
76     0x06, 0x8c, 0x29, 0x96, 0xfe, 0xa2, 0x71, 0x4d,
77     0xf3, 0xf8, 0x2e, 0x58, 0xdb, 0x0d, 0x5a, 0x5f,
78     0x15, 0x28, 0xf5, 0x74, 0x07, 0xce, 0x25, 0xaf,
79     0x2b, 0x12, 0xe6, 0xd0, 0xdb, 0x2c, 0xdc, 0xc3,
80     0x7f, 0xf0, 0x3e, 0x3a, 0x13, 0xa4, 0xdc, 0xe2,
81     0xf9, 0x6c, 0x54, 0xe2, 0xd8, 0xea, 0xc8, 0x88,
82     0x00, 0x21, 0x86, 0x9c, 0x6a, 0xd8, 0xcb, 0x4e,
83     0x14, 0x6a, 0xf9, 0x4d, 0xd2, 0x7e, 0xb2, 0x32,
84     0x03, 0xc6, 0x14, 0x4b, 0x7f, 0xd1, 0xb8, 0xa6,
85     0x79, 0x7c, 0x17, 0xac, 0xed, 0x06, 0xad, 0xaf,
86     0x0a, 0x94, 0x7a, 0xba, 0x03, 0xe7, 0x92, 0xd7,
87     0x15, 0x09, 0x73, 0xe8, 0x6d, 0x16, 0xee, 0xe1,
88     0x3f, 0x78, 0x1f, 0x9d, 0x09, 0x52, 0x6e, 0xf1,
89     0x7c, 0x36, 0x2a, 0x71, 0x6c, 0x75, 0x64, 0x44,
90     0x80, 0x10, 0x43, 0x4e, 0x35, 0xec, 0x65, 0x27,
91     0x0a, 0xb5, 0xfc, 0x26, 0x69, 0x3f, 0x59, 0x99,
92     0x01, 0x63, 0x8a, 0xa5, 0xbf, 0x68, 0x5c, 0xd3,
93     0x3c, 0xbe, 0x0b, 0xd6, 0x76, 0x83, 0xd6, 0x57,
94     0x05, 0x4a, 0x3d, 0xdd, 0x81, 0x73, 0xc9, 0xeb,
95     0x8a, 0x84, 0x39, 0xf4, 0x36, 0x0b, 0xf7
96 };
97 
98 static const uint8_t g_ble_ll_dtm_prbs15_data[] =
99 {
100     0xff, 0x7f, 0xf0, 0x3e, 0x3a, 0x13, 0xa4, 0xdc,
101     0xe2, 0xf9, 0x6c, 0x54, 0xe2, 0xd8, 0xea, 0xc8,
102     0x88, 0x00, 0x21, 0x86, 0x9c, 0x6a, 0xd8, 0xcb,
103     0x4e, 0x14, 0x6a, 0xf9, 0x4d, 0xd2, 0x7e, 0xb2,
104     0x32, 0x03, 0xc6, 0x14, 0x4b, 0x7f, 0xd1, 0xb8,
105     0xa6, 0x79, 0x7c, 0x17, 0xac, 0xed, 0x06, 0xad,
106     0xaf, 0x0a, 0x94, 0x7a, 0xba, 0x03, 0xe7, 0x92,
107     0xd7, 0x15, 0x09, 0x73, 0xe8, 0x6d, 0x16, 0xee,
108     0xe1, 0x3f, 0x78, 0x1f, 0x9d, 0x09, 0x52, 0x6e,
109     0xf1, 0x7c, 0x36, 0x2a, 0x71, 0x6c, 0x75, 0x64,
110     0x44, 0x80, 0x10, 0x43, 0x4e, 0x35, 0xec, 0x65,
111     0x27, 0x0a, 0xb5, 0xfc, 0x26, 0x69, 0x3f, 0x59,
112     0x99, 0x01, 0x63, 0x8a, 0xa5, 0xbf, 0x68, 0x5c,
113     0xd3, 0x3c, 0xbe, 0x0b, 0xd6, 0x76, 0x83, 0xd6,
114     0x57, 0x05, 0x4a, 0x3d, 0xdd, 0x81, 0x73, 0xc9,
115     0xeb, 0x8a, 0x84, 0x39, 0xf4, 0x36, 0x0b, 0xf7,
116     0xf0, 0x1f, 0xbc, 0x8f, 0xce, 0x04, 0x29, 0xb7,
117     0x78, 0x3e, 0x1b, 0x95, 0x38, 0xb6, 0x3a, 0x32,
118     0x22, 0x40, 0x88, 0x21, 0xa7, 0x1a, 0xf6, 0xb2,
119     0x13, 0x85, 0x5a, 0x7e, 0x93, 0xb4, 0x9f, 0xac,
120     0xcc, 0x80, 0x31, 0xc5, 0xd2, 0x5f, 0x34, 0xae,
121     0x69, 0x1e, 0xdf, 0x05, 0x6b, 0xbb, 0x41, 0xeb,
122     0xab, 0x02, 0xa5, 0x9e, 0xee, 0xc0, 0xb9, 0xe4,
123     0x75, 0x45, 0xc2, 0x1c, 0x7a, 0x9b, 0x85, 0x7b,
124     0xf8, 0x0f, 0xde, 0x47, 0x67, 0x82, 0x94, 0x5b,
125     0x3c, 0x9f, 0x8d, 0x4a, 0x1c, 0x5b, 0x1d, 0x19,
126     0x11, 0x20, 0xc4, 0x90, 0x53, 0x0d, 0x7b, 0xd9,
127     0x89, 0x42, 0x2d, 0xbf, 0x49, 0xda, 0x4f, 0x56,
128     0x66, 0xc0, 0x98, 0x62, 0xe9, 0x2f, 0x1a, 0xd7,
129     0x34, 0x8f, 0xef, 0x82, 0xb5, 0xdd, 0xa0, 0xf5,
130     0x55, 0x81, 0x52, 0x4f, 0x77, 0xe0, 0x5c, 0xf2,
131     0xba, 0x22, 0x61, 0x0e, 0xbd, 0xcd, 0xc2
132 };
133 
134 static const uint8_t channel_rf_to_index[] = {
135         37,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 38, 11 ,12, 13, 14, 15,
136         16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
137         34, 35, 36, 39
138 };
139 
140 #define BLE_DTM_SYNC_WORD          (0x71764129)
141 #define BLE_DTM_CRC                (0x555555)
142 
143 static void
ble_ll_dtm_set_next(struct dtm_ctx * ctx)144 ble_ll_dtm_set_next(struct dtm_ctx *ctx)
145 {
146     struct ble_ll_sched_item *sch = &ctx->sch;
147 
148     sch->start_time += ctx->itvl_ticks;
149     sch->remainder += ctx->itvl_rem_usec;
150     if (sch->remainder > 30) {
151        sch->start_time++;
152        sch->remainder -= 30;
153     }
154 
155     sch->start_time -= g_ble_ll_sched_offset_ticks;
156 }
157 
158 static void
ble_ll_dtm_ev_tx_resched_cb(struct ble_npl_event * evt)159 ble_ll_dtm_ev_tx_resched_cb(struct ble_npl_event *evt) {
160     /* It is called in LL context */
161     struct dtm_ctx *ctx = ble_npl_event_get_arg(evt);
162     int rc;
163     os_sr_t sr;
164 
165     OS_ENTER_CRITICAL(sr);
166     if (!ctx->active || !ctx->om) {
167         OS_EXIT_CRITICAL(sr);
168         return;
169     }
170     OS_EXIT_CRITICAL(sr);
171 
172     ble_ll_dtm_set_next(ctx);
173     rc = ble_ll_sched_dtm(&ctx->sch);
174     BLE_LL_ASSERT(rc == 0);
175 }
176 
177 static int ble_ll_dtm_rx_start(void);
178 
179 static void
ble_ll_dtm_ev_rx_restart_cb(struct ble_npl_event * evt)180 ble_ll_dtm_ev_rx_restart_cb(struct ble_npl_event *evt) {
181     if (ble_ll_dtm_rx_start() != 0) {
182         ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt);
183         STATS_INC(ble_ll_dtm_stats, rx_failed);
184     }
185 }
186 
187 static void
ble_ll_dtm_tx_done(void * arg)188 ble_ll_dtm_tx_done(void *arg)
189 {
190     struct dtm_ctx *ctx;
191 
192     ctx = arg;
193     if (!ctx->active) {
194         return;
195     }
196 
197     /* Reschedule event in LL context */
198     ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &ctx->evt);
199 
200     ble_ll_state_set(BLE_LL_STATE_STANDBY);
201 }
202 
203 static int
ble_ll_dtm_tx_sched_cb(struct ble_ll_sched_item * sch)204 ble_ll_dtm_tx_sched_cb(struct ble_ll_sched_item *sch)
205 {
206     struct dtm_ctx *ctx = sch->cb_arg;
207     int rc;
208 
209     if (!ctx->active) {
210         return BLE_LL_SCHED_STATE_DONE;
211     }
212 
213     rc = ble_phy_setchan(channel_rf_to_index[ctx->rf_channel],
214                                             BLE_DTM_SYNC_WORD, BLE_DTM_CRC);
215     if (rc != 0) {
216         BLE_LL_ASSERT(0);
217         return BLE_LL_SCHED_STATE_DONE;
218     }
219 
220 #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY))
221     ble_phy_mode_set(ctx->phy_mode, ctx->phy_mode);
222 #endif
223     ble_phy_set_txend_cb(ble_ll_dtm_tx_done, ctx);
224     ble_phy_txpwr_set(0);
225 
226     sch->start_time += g_ble_ll_sched_offset_ticks;
227 
228     rc = ble_phy_tx_set_start_time(sch->start_time, sch->remainder);
229     if (rc) {
230         goto resched;
231     }
232 
233     rc = ble_phy_tx(ble_ll_tx_mbuf_pducb, ctx->om, BLE_PHY_TRANSITION_NONE);
234     if (rc) {
235         goto resched;
236     }
237 
238     ble_ll_state_set(BLE_LL_STATE_DTM);
239 
240     return BLE_LL_SCHED_STATE_DONE;
241 
242 resched:
243     /* Reschedule from LL task if late for this PDU */
244     ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &ctx->evt);
245 
246     STATS_INC(ble_ll_dtm_stats, tx_failed);
247 
248     return BLE_LL_SCHED_STATE_DONE;
249 }
250 
251 static void
ble_ll_dtm_calculate_itvl(struct dtm_ctx * ctx,uint8_t len,int phy_mode)252 ble_ll_dtm_calculate_itvl(struct dtm_ctx *ctx, uint8_t len, int phy_mode)
253 {
254     uint32_t l;
255     uint32_t itvl_usec;
256     uint32_t itvl_ticks;
257 
258     /* Calculate interval as per spec Bluetooth 5.0 Vol 6. Part F, 4.1.6 */
259     l = ble_ll_pdu_tx_time_get(len + BLE_LL_PDU_HDR_LEN, phy_mode);
260     itvl_usec = ((l + 249 + 624) / 625) * 625;
261 
262     itvl_ticks = os_cputime_usecs_to_ticks(itvl_usec);
263     ctx->itvl_rem_usec = (itvl_usec - os_cputime_ticks_to_usecs(itvl_ticks));
264     if (ctx->itvl_rem_usec == 31) {
265         ctx->itvl_rem_usec = 0;
266         ++itvl_ticks;
267     }
268     ctx->itvl_ticks = itvl_ticks;
269 }
270 
271 static int
ble_ll_dtm_tx_create_ctx(uint8_t packet_payload,uint8_t len,uint8_t rf_channel,uint8_t phy_mode)272 ble_ll_dtm_tx_create_ctx(uint8_t packet_payload, uint8_t len,
273                          uint8_t rf_channel, uint8_t phy_mode)
274 {
275     int rc = 0;
276     uint8_t byte_pattern;
277     struct ble_mbuf_hdr *ble_hdr;
278     struct os_mbuf *m;
279     struct ble_ll_sched_item *sch = &g_ble_ll_dtm_ctx.sch;
280 
281     /* MSYS is big enough to get continues memory */
282     m = os_msys_get_pkthdr(len, sizeof(struct ble_mbuf_hdr));
283     g_ble_ll_dtm_ctx.om = m;
284     BLE_LL_ASSERT(g_ble_ll_dtm_ctx.om);
285 
286     g_ble_ll_dtm_ctx.phy_mode = phy_mode;
287     g_ble_ll_dtm_ctx.rf_channel = rf_channel;
288 
289     /* Set BLE transmit header */
290     ble_hdr = BLE_MBUF_HDR_PTR(m);
291     ble_hdr->txinfo.flags = 0;
292     ble_hdr->txinfo.offset = 0;
293     ble_hdr->txinfo.pyld_len = len;
294     ble_hdr->txinfo.hdr_byte = packet_payload;
295 
296     switch(packet_payload) {
297     case 0x00:
298         if (os_mbuf_copyinto(m, 0, &g_ble_ll_dtm_prbs9_data, len)) {
299             return 1;
300         }
301         goto schedule;
302     case 0x01:
303         byte_pattern = 0x0F;
304         break;
305     case 0x02:
306         byte_pattern = 0x55;
307         break;
308     case 0x03:
309         if (os_mbuf_copyinto(m, 0, &g_ble_ll_dtm_prbs15_data, len)) {
310             return 1;
311         }
312         goto schedule;
313     case 0x04:
314         byte_pattern = 0xFF;
315         break;
316     case 0x05:
317         byte_pattern = 0x00;
318         break;
319     case 0x06:
320         byte_pattern = 0xF0;
321         break;
322     case 0x07:
323         byte_pattern = 0xAA;
324         break;
325     default:
326         return 1;
327     }
328 
329     for (rc = 0; rc < len; rc++) {
330         if (os_mbuf_copyinto(m, rc, &byte_pattern, 1)) {
331             return 1;
332         }
333     }
334 
335 schedule:
336 
337     sch->sched_cb = ble_ll_dtm_tx_sched_cb;
338     sch->cb_arg = &g_ble_ll_dtm_ctx;
339     sch->sched_type = BLE_LL_SCHED_TYPE_DTM;
340     sch->start_time =  os_cputime_get32() +
341                                        os_cputime_usecs_to_ticks(5000);
342 
343     /* Prepare os_event */
344     ble_npl_event_init(&g_ble_ll_dtm_ctx.evt, ble_ll_dtm_ev_tx_resched_cb,
345                        &g_ble_ll_dtm_ctx);
346 
347     ble_ll_dtm_calculate_itvl(&g_ble_ll_dtm_ctx, len, phy_mode);
348 
349     /* Set some start point for TX packets */
350     rc = ble_ll_sched_dtm(sch);
351     BLE_LL_ASSERT(rc == 0);
352 
353     ble_phy_enable_dtm();
354 
355     g_ble_ll_dtm_ctx.active = 1;
356     return 0;
357 }
358 
359 static int
ble_ll_dtm_rx_start(void)360 ble_ll_dtm_rx_start(void)
361 {
362     os_sr_t sr;
363     int rc;
364 
365     rc = ble_phy_setchan(channel_rf_to_index[g_ble_ll_dtm_ctx.rf_channel],
366                          BLE_DTM_SYNC_WORD, BLE_DTM_CRC);
367     if (rc) {
368         return rc;
369     }
370 
371 #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY))
372     ble_phy_mode_set(g_ble_ll_dtm_ctx.phy_mode, g_ble_ll_dtm_ctx.phy_mode);
373 #endif
374 
375     OS_ENTER_CRITICAL(sr);
376     rc = ble_phy_rx_set_start_time(os_cputime_get32() +
377                                    g_ble_ll_sched_offset_ticks, 0);
378     OS_EXIT_CRITICAL(sr);
379     if (rc && rc != BLE_PHY_ERR_RX_LATE) {
380         return rc;
381     }
382 
383     ble_ll_state_set(BLE_LL_STATE_DTM);
384 
385 #ifdef BLE_XCVR_RFCLK
386     if (ble_ll_xcvr_rfclk_state() == BLE_RFCLK_STATE_OFF) {
387         ble_ll_xcvr_rfclk_start_now(os_cputime_get32());
388     }
389 #endif
390 
391     return 0;
392 }
393 
394 static int
ble_ll_dtm_rx_create_ctx(uint8_t rf_channel,uint8_t phy_mode)395 ble_ll_dtm_rx_create_ctx(uint8_t rf_channel, uint8_t phy_mode)
396 {
397     g_ble_ll_dtm_ctx.phy_mode = phy_mode;
398     g_ble_ll_dtm_ctx.rf_channel = rf_channel;
399     g_ble_ll_dtm_ctx.active = 1;
400 
401     STATS_CLEAR(ble_ll_dtm_stats, rx_count);
402 
403     ble_npl_event_init(&g_ble_ll_dtm_ctx.evt, ble_ll_dtm_ev_rx_restart_cb,
404                        NULL);
405 
406     if (ble_ll_dtm_rx_start() != 0) {
407         return 1;
408     }
409 
410     ble_phy_enable_dtm();
411 
412     return 0;
413 }
414 
415 static void
ble_ll_dtm_ctx_free(struct dtm_ctx * ctx)416 ble_ll_dtm_ctx_free(struct dtm_ctx * ctx)
417 {
418     os_sr_t sr;
419 
420     OS_ENTER_CRITICAL(sr);
421     if (!ctx->active) {
422         OS_EXIT_CRITICAL(sr);
423         return;
424     }
425     OS_EXIT_CRITICAL(sr);
426 
427     ble_ll_sched_rmv_elem(&ctx->sch);
428 
429     ble_phy_disable();
430     ble_phy_disable_dtm();
431     ble_ll_state_set(BLE_LL_STATE_STANDBY);
432 #ifdef BLE_XCVR_RFCLK
433     ble_ll_xcvr_rfclk_stop();
434 #endif
435 
436     os_mbuf_free_chain(ctx->om);
437     memset(ctx, 0, sizeof(*ctx));
438 }
439 
440 int
ble_ll_dtm_tx_test(uint8_t * cmdbuf,bool enhanced)441 ble_ll_dtm_tx_test(uint8_t *cmdbuf, bool enhanced)
442 {
443     uint8_t tx_chan = cmdbuf[0];
444     uint8_t len = cmdbuf[1];
445     uint8_t packet_payload = cmdbuf[2];
446     uint8_t phy_mode = BLE_PHY_MODE_1M;
447 
448     if (g_ble_ll_dtm_ctx.active) {
449         return BLE_ERR_CTLR_BUSY;
450     }
451 
452     if (enhanced) {
453         switch (cmdbuf[3]) {
454         case BLE_HCI_LE_PHY_1M:
455             phy_mode = BLE_PHY_MODE_1M;
456             break;
457 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
458         case BLE_HCI_LE_PHY_2M:
459             phy_mode = BLE_PHY_MODE_2M;
460             break;
461 #endif
462 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
463         case BLE_HCI_LE_PHY_CODED_S8:
464             phy_mode = BLE_PHY_MODE_CODED_125KBPS;
465             break;
466         case BLE_HCI_LE_PHY_CODED_S2:
467             phy_mode = BLE_PHY_MODE_CODED_500KBPS;
468             break;
469 #endif
470         default:
471             return BLE_ERR_INV_HCI_CMD_PARMS;
472         }
473     }
474 
475     if (tx_chan > 0x27 || packet_payload > 0x07) {
476         return BLE_ERR_INV_HCI_CMD_PARMS;
477     }
478 
479     if (ble_ll_dtm_tx_create_ctx(packet_payload, len, tx_chan, phy_mode)) {
480         return BLE_ERR_UNSPECIFIED;
481     }
482 
483     return BLE_ERR_SUCCESS;
484 }
485 
ble_ll_dtm_rx_test(uint8_t * cmdbuf,bool enhanced)486 int ble_ll_dtm_rx_test(uint8_t *cmdbuf, bool enhanced)
487 {
488     uint8_t rx_chan = cmdbuf[0];
489     uint8_t phy_mode = BLE_PHY_MODE_1M;
490 
491     if (g_ble_ll_dtm_ctx.active) {
492         return BLE_ERR_CTLR_BUSY;
493     }
494 
495     /*XXX What to do with modulation cmdbuf[2]? */
496 
497     if (enhanced) {
498         switch (cmdbuf[1]) {
499         case BLE_HCI_LE_PHY_1M:
500             phy_mode = BLE_PHY_MODE_1M;
501             break;
502 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
503         case BLE_HCI_LE_PHY_2M:
504             phy_mode = BLE_PHY_MODE_2M;
505             break;
506 #endif
507 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
508         case BLE_HCI_LE_PHY_CODED:
509             phy_mode = BLE_PHY_MODE_CODED_500KBPS;
510             break;
511 #endif
512         default:
513             return BLE_ERR_INV_HCI_CMD_PARMS;
514         }
515     }
516 
517     if (rx_chan > 0x27) {
518         return BLE_ERR_INV_HCI_CMD_PARMS;
519     }
520 
521     if (ble_ll_dtm_rx_create_ctx(rx_chan, phy_mode)) {
522         return BLE_ERR_UNSPECIFIED;
523     }
524 
525     return BLE_ERR_SUCCESS;
526 }
527 
ble_ll_dtm_end_test(uint8_t * rsp,uint8_t * rsplen)528 int ble_ll_dtm_end_test(uint8_t *rsp, uint8_t *rsplen)
529 {
530     put_le16(rsp, g_ble_ll_dtm_ctx. num_of_packets);
531     *rsplen = 2;
532 
533     ble_ll_dtm_ctx_free(&g_ble_ll_dtm_ctx);
534     return BLE_ERR_SUCCESS;
535 }
536 
ble_ll_dtm_rx_isr_start(struct ble_mbuf_hdr * rxhdr,uint32_t aa)537 int ble_ll_dtm_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa)
538 {
539     return 0;
540 }
541 
542 void
ble_ll_dtm_rx_pkt_in(struct os_mbuf * rxpdu,struct ble_mbuf_hdr * hdr)543 ble_ll_dtm_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
544 {
545     if (BLE_MBUF_HDR_CRC_OK(hdr)) {
546         /* XXX Compare data. */
547         g_ble_ll_dtm_ctx.num_of_packets++;
548         STATS_INC(ble_ll_dtm_stats, rx_count);
549     }
550 
551     if (ble_ll_dtm_rx_start() != 0) {
552         ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt);
553         STATS_INC(ble_ll_dtm_stats, rx_failed);
554     }
555 }
556 
557 int
ble_ll_dtm_rx_isr_end(uint8_t * rxbuf,struct ble_mbuf_hdr * rxhdr)558 ble_ll_dtm_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
559 {
560     struct os_mbuf *rxpdu;
561 
562     if (!g_ble_ll_dtm_ctx.active) {
563         return -1;
564     }
565 
566     rxpdu = ble_ll_rxpdu_alloc(rxbuf[1] + BLE_LL_PDU_HDR_LEN);
567 
568     /* Copy the received pdu and hand it up */
569     if (rxpdu) {
570         ble_phy_rxpdu_copy(rxbuf, rxpdu);
571         ble_ll_rx_pdu_in(rxpdu);
572     }
573 
574     return 0;
575 }
576 
577 void
ble_ll_dtm_wfr_timer_exp(void)578 ble_ll_dtm_wfr_timer_exp(void)
579 {
580     /* Should not be needed */
581     BLE_LL_ASSERT(0);
582 }
583 
584 
585 void
ble_ll_dtm_reset(void)586 ble_ll_dtm_reset(void)
587 {
588     ble_ll_dtm_ctx_free(&g_ble_ll_dtm_ctx);
589 }
590 
591 void
ble_ll_dtm_init(void)592 ble_ll_dtm_init(void)
593 {
594     int rc;
595 
596     rc = stats_init_and_reg(STATS_HDR(ble_ll_dtm_stats),
597                             STATS_SIZE_INIT_PARMS(ble_ll_dtm_stats, STATS_SIZE_32),
598                             STATS_NAME_INIT_PARMS(ble_ll_dtm_stats),
599                             "ble_ll_dtm");
600     SYSINIT_PANIC_ASSERT(rc == 0);
601 }
602 #endif
603