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 <stdint.h>
21 #include <string.h>
22 #include <assert.h>
23 #include "syscfg/syscfg.h"
24 #include "os/os.h"
25 #include "ble/xcvr.h"
26 #include "nimble/ble.h"
27 #include "nimble/nimble_opt.h"
28 #include "controller/ble_phy.h"
29 #include "controller/ble_ll.h"
30
31 /* BLE PHY data structure */
32 struct ble_phy_obj
33 {
34 uint8_t phy_stats_initialized;
35 int8_t phy_txpwr_dbm;
36 uint8_t phy_chan;
37 uint8_t phy_state;
38 uint8_t phy_transition;
39 uint8_t phy_rx_started;
40 uint8_t phy_encrypted;
41 uint8_t phy_privacy;
42 uint8_t phy_tx_pyld_len;
43 uint32_t phy_aar_scratch;
44 uint32_t phy_access_address;
45 struct ble_mbuf_hdr rxhdr;
46 void *txend_arg;
47 uint8_t *rxdptr;
48 ble_phy_tx_end_func txend_cb;
49 };
50 struct ble_phy_obj g_ble_phy_data;
51
52 /* Statistics */
53 struct ble_phy_statistics
54 {
55 uint32_t tx_good;
56 uint32_t tx_fail;
57 uint32_t tx_late;
58 uint32_t tx_bytes;
59 uint32_t rx_starts;
60 uint32_t rx_aborts;
61 uint32_t rx_valid;
62 uint32_t rx_crc_err;
63 uint32_t phy_isrs;
64 uint32_t radio_state_errs;
65 uint32_t no_bufs;
66 };
67
68 struct ble_phy_statistics g_ble_phy_stats;
69
70 static uint8_t g_ble_phy_tx_buf[BLE_PHY_MAX_PDU_LEN];
71
72 /* XCVR object to emulate transceiver */
73 struct xcvr_data
74 {
75 uint32_t irq_status;
76 };
77 static struct xcvr_data g_xcvr_data;
78
79 #define BLE_XCVR_IRQ_F_RX_START (0x00000001)
80 #define BLE_XCVR_IRQ_F_RX_END (0x00000002)
81 #define BLE_XCVR_IRQ_F_TX_START (0x00000004)
82 #define BLE_XCVR_IRQ_F_TX_END (0x00000008)
83 #define BLE_XCVR_IRQ_F_BYTE_CNTR (0x00000010)
84
85 /* "Rail" power level if outside supported range */
86 #define BLE_XCVR_TX_PWR_MAX_DBM (30)
87 #define BLE_XCVR_TX_PWR_MIN_DBM (-20)
88
89 /* Statistics */
90 STATS_SECT_START(ble_phy_stats)
91 STATS_SECT_ENTRY(phy_isrs)
92 STATS_SECT_ENTRY(tx_good)
93 STATS_SECT_ENTRY(tx_fail)
94 STATS_SECT_ENTRY(tx_late)
95 STATS_SECT_ENTRY(tx_bytes)
96 STATS_SECT_ENTRY(rx_starts)
97 STATS_SECT_ENTRY(rx_aborts)
98 STATS_SECT_ENTRY(rx_valid)
99 STATS_SECT_ENTRY(rx_crc_err)
100 STATS_SECT_ENTRY(rx_late)
101 STATS_SECT_ENTRY(no_bufs)
102 STATS_SECT_ENTRY(radio_state_errs)
103 STATS_SECT_ENTRY(rx_hw_err)
104 STATS_SECT_ENTRY(tx_hw_err)
105 STATS_SECT_END
106 STATS_SECT_DECL(ble_phy_stats) ble_phy_stats;
107
108 STATS_NAME_START(ble_phy_stats)
STATS_NAME(ble_phy_stats,phy_isrs)109 STATS_NAME(ble_phy_stats, phy_isrs)
110 STATS_NAME(ble_phy_stats, tx_good)
111 STATS_NAME(ble_phy_stats, tx_fail)
112 STATS_NAME(ble_phy_stats, tx_late)
113 STATS_NAME(ble_phy_stats, tx_bytes)
114 STATS_NAME(ble_phy_stats, rx_starts)
115 STATS_NAME(ble_phy_stats, rx_aborts)
116 STATS_NAME(ble_phy_stats, rx_valid)
117 STATS_NAME(ble_phy_stats, rx_crc_err)
118 STATS_NAME(ble_phy_stats, rx_late)
119 STATS_NAME(ble_phy_stats, no_bufs)
120 STATS_NAME(ble_phy_stats, radio_state_errs)
121 STATS_NAME(ble_phy_stats, rx_hw_err)
122 STATS_NAME(ble_phy_stats, tx_hw_err)
123 STATS_NAME_END(ble_phy_stats)
124
125 /* XXX: TODO:
126
127 * 1) Test the following to make sure it works: suppose an event is already
128 * set to 1 and the interrupt is not enabled. What happens if you enable the
129 * interrupt with the event bit already set to 1
130 * 2) how to deal with interrupts?
131 */
132 static uint32_t
133 ble_xcvr_get_irq_status(void)
134 {
135 return g_xcvr_data.irq_status;
136 }
137
138 static void
ble_xcvr_clear_irq(uint32_t mask)139 ble_xcvr_clear_irq(uint32_t mask)
140 {
141 g_xcvr_data.irq_status &= ~mask;
142 }
143
144 /**
145 * Copies the data from the phy receive buffer into a mbuf chain.
146 *
147 * @param dptr Pointer to receive buffer
148 * @param rxpdu Pointer to already allocated mbuf chain
149 *
150 * NOTE: the packet header already has the total mbuf length in it. The
151 * lengths of the individual mbufs are not set prior to calling.
152 *
153 */
154 void
ble_phy_rxpdu_copy(uint8_t * dptr,struct os_mbuf * rxpdu)155 ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu)
156 {
157 uint16_t rem_bytes;
158 uint16_t mb_bytes;
159 uint16_t copylen;
160 uint32_t *dst;
161 uint32_t *src;
162 struct os_mbuf *m;
163 struct ble_mbuf_hdr *ble_hdr;
164 struct os_mbuf_pkthdr *pkthdr;
165
166 /* Better be aligned */
167 assert(((uint32_t)dptr & 3) == 0);
168
169 pkthdr = OS_MBUF_PKTHDR(rxpdu);
170 rem_bytes = pkthdr->omp_len;
171
172 /* Fill in the mbuf pkthdr first. */
173 dst = (uint32_t *)(rxpdu->om_data);
174 src = (uint32_t *)dptr;
175
176 mb_bytes = (rxpdu->om_omp->omp_databuf_len - rxpdu->om_pkthdr_len - 4);
177 copylen = min(mb_bytes, rem_bytes);
178 copylen &= 0xFFFC;
179 rem_bytes -= copylen;
180 mb_bytes -= copylen;
181 rxpdu->om_len = copylen;
182 while (copylen > 0) {
183 *dst = *src;
184 ++dst;
185 ++src;
186 copylen -= 4;
187 }
188
189 /* Copy remaining bytes */
190 m = rxpdu;
191 while (rem_bytes > 0) {
192 /* If there are enough bytes in the mbuf, copy them and leave */
193 if (rem_bytes <= mb_bytes) {
194 memcpy(m->om_data + m->om_len, src, rem_bytes);
195 m->om_len += rem_bytes;
196 break;
197 }
198
199 m = SLIST_NEXT(m, om_next);
200 assert(m != NULL);
201
202 mb_bytes = m->om_omp->omp_databuf_len;
203 copylen = min(mb_bytes, rem_bytes);
204 copylen &= 0xFFFC;
205 rem_bytes -= copylen;
206 mb_bytes -= copylen;
207 m->om_len = copylen;
208 dst = (uint32_t *)m->om_data;
209 while (copylen > 0) {
210 *dst = *src;
211 ++dst;
212 ++src;
213 copylen -= 4;
214 }
215 }
216
217 /* Copy ble header */
218 ble_hdr = BLE_MBUF_HDR_PTR(rxpdu);
219 memcpy(ble_hdr, &g_ble_phy_data.rxhdr, sizeof(struct ble_mbuf_hdr));
220 }
221
222 void
ble_phy_isr(void)223 ble_phy_isr(void)
224 {
225 int rc;
226 uint8_t transition;
227 uint32_t irq_en;
228 struct ble_mbuf_hdr *ble_hdr;
229
230 /* Check for disabled event. This only happens for transmits now */
231 irq_en = ble_xcvr_get_irq_status();
232 if (irq_en & BLE_XCVR_IRQ_F_TX_END) {
233
234 /* Better be in TX state! */
235 assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX);
236 ble_xcvr_clear_irq(BLE_XCVR_IRQ_F_TX_END);
237
238 transition = g_ble_phy_data.phy_transition;
239 if (transition == BLE_PHY_TRANSITION_TX_RX) {
240 /* Disable the phy */
241 /* XXX: count no bufs? */
242 ble_phy_disable();
243 } else {
244 /* Better not be going from rx to tx! */
245 assert(transition == BLE_PHY_TRANSITION_NONE);
246 }
247 }
248
249 /* We get this if we have started to receive a frame */
250 if (irq_en & BLE_XCVR_IRQ_F_RX_START) {
251
252 ble_xcvr_clear_irq(BLE_XCVR_IRQ_F_RX_START);
253
254 /* Call Link Layer receive start function */
255 rc = ble_ll_rx_start(g_ble_phy_data.rxdptr, g_ble_phy_data.phy_chan,
256 &g_ble_phy_data.rxhdr);
257 if (rc >= 0) {
258 /* XXX: set rx end enable isr */
259 } else {
260 /* Disable PHY */
261 ble_phy_disable();
262 irq_en = 0;
263 ++g_ble_phy_stats.rx_aborts;
264 }
265
266 /* Count rx starts */
267 ++g_ble_phy_stats.rx_starts;
268 }
269
270 /* Receive packet end (we dont enable this for transmit) */
271 if (irq_en & BLE_XCVR_IRQ_F_RX_END) {
272
273 ble_xcvr_clear_irq(BLE_XCVR_IRQ_F_RX_END);
274
275 /* Construct BLE header before handing up */
276 ble_hdr = &g_ble_phy_data.rxhdr;
277 ble_hdr->rxinfo.flags = 0;
278 ble_hdr->rxinfo.rssi = -77; /* XXX: dummy rssi */
279 ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan;
280 ble_hdr->rxinfo.phy = BLE_PHY_1M;
281 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
282 ble_hdr->rxinfo.aux_data = NULL;
283 #endif
284
285 /* Count PHY valid packets */
286 ++g_ble_phy_stats.rx_valid;
287 ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CRC_OK;
288
289 /* Call Link Layer receive payload function */
290 rc = ble_ll_rx_end(g_ble_phy_data.rxdptr, ble_hdr);
291 if (rc < 0) {
292 /* Disable the PHY. */
293 ble_phy_disable();
294 }
295 }
296
297 /* Count # of interrupts */
298 ++g_ble_phy_stats.phy_isrs;
299 }
300
301 /**
302 * ble phy init
303 *
304 * Initialize the PHY. This is expected to be called once.
305 *
306 * @return int 0: success; PHY error code otherwise
307 */
308 int
ble_phy_init(void)309 ble_phy_init(void)
310 {
311 /* Set phy channel to an invalid channel so first set channel works */
312 g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE;
313 g_ble_phy_data.phy_chan = BLE_PHY_NUM_CHANS;
314
315 /* XXX: emulate ISR? */
316
317 return 0;
318 }
319
320 int
ble_phy_rx(void)321 ble_phy_rx(void)
322 {
323 /* Check radio state */
324 if (ble_phy_state_get() != BLE_PHY_STATE_IDLE) {
325 ble_phy_disable();
326 ++g_ble_phy_stats.radio_state_errs;
327 return BLE_PHY_ERR_RADIO_STATE;
328 }
329
330 g_ble_phy_data.phy_state = BLE_PHY_STATE_RX;
331
332 return 0;
333 }
334
335 void
ble_phy_restart_rx(void)336 ble_phy_restart_rx(void)
337 {
338 }
339
340 #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
341 /**
342 * Called to enable encryption at the PHY. Note that this state will persist
343 * in the PHY; in other words, if you call this function you have to call
344 * disable so that future PHY transmits/receives will not be encrypted.
345 *
346 * @param pkt_counter
347 * @param iv
348 * @param key
349 * @param is_master
350 */
351 void
ble_phy_encrypt_enable(uint64_t pkt_counter,uint8_t * iv,uint8_t * key,uint8_t is_master)352 ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key,
353 uint8_t is_master)
354 {
355 }
356
357 void
ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter,int dir)358 ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir)
359 {
360 }
361
362 void
ble_phy_encrypt_disable(void)363 ble_phy_encrypt_disable(void)
364 {
365 }
366 #endif
367
368 void
ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb,void * arg)369 ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg)
370 {
371 /* Set transmit end callback and arg */
372 g_ble_phy_data.txend_cb = txend_cb;
373 g_ble_phy_data.txend_arg = arg;
374 }
375
376 /**
377 * Called to set the start time of a transmission.
378 *
379 * This function is called to set the start time when we are not going from
380 * rx to tx automatically.
381 *
382 * NOTE: care must be taken when calling this function. The channel should
383 * already be set.
384 *
385 * @param cputime
386 * @param rem_usecs
387 *
388 * @return int
389 */
390 int
ble_phy_tx_set_start_time(uint32_t cputime,uint8_t rem_usecs)391 ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
392 {
393 return 0;
394 }
395
396 /**
397 * Called to set the start time of a reception
398 *
399 * This function acts a bit differently than transmit. If we are late getting
400 * here we will still attempt to receive.
401 *
402 * NOTE: care must be taken when calling this function. The channel should
403 * already be set.
404 *
405 * @param cputime
406 * @param rem_usecs
407 *
408 * @return int
409 */
410 int
ble_phy_rx_set_start_time(uint32_t cputime,uint8_t rem_usecs)411 ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
412 {
413 return 0;
414 }
415
416
417 int
ble_phy_tx(ble_phy_tx_pducb_t pducb,void * pducb_arg,uint8_t end_trans)418 ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans)
419 {
420 uint8_t hdr_byte;
421 int rc;
422
423 if (ble_phy_state_get() != BLE_PHY_STATE_IDLE) {
424 ble_phy_disable();
425 ++g_ble_phy_stats.radio_state_errs;
426 return BLE_PHY_ERR_RADIO_STATE;
427 }
428
429 /* Select tx address */
430 if (g_ble_phy_data.phy_chan < BLE_PHY_NUM_DATA_CHANS) {
431 /* XXX: fix this */
432 assert(0);
433 } else {
434 }
435
436 /* Set the PHY transition */
437 g_ble_phy_data.phy_transition = end_trans;
438
439 /* Set phy state to transmitting and count packet statistics */
440 g_ble_phy_data.phy_state = BLE_PHY_STATE_TX;
441 ++g_ble_phy_stats.tx_good;
442 g_ble_phy_stats.tx_bytes += pducb(g_ble_phy_tx_buf, pducb_arg, &hdr_byte) +
443 BLE_LL_PDU_HDR_LEN;
444 rc = BLE_ERR_SUCCESS;
445
446 return rc;
447 }
448
449 /**
450 * ble phy txpwr set
451 *
452 * Set the transmit output power (in dBm).
453 *
454 * NOTE: If the output power specified is within the BLE limits but outside
455 * the chip limits, we "rail" the power level so we dont exceed the min/max
456 * chip values.
457 *
458 * @param dbm Power output in dBm.
459 *
460 * @return int 0: success; anything else is an error
461 */
462 int
ble_phy_txpwr_set(int dbm)463 ble_phy_txpwr_set(int dbm)
464 {
465 /* Check valid range */
466 assert(dbm <= BLE_PHY_MAX_PWR_DBM);
467
468 /* "Rail" power level if outside supported range */
469 if (dbm > BLE_XCVR_TX_PWR_MAX_DBM) {
470 dbm = BLE_XCVR_TX_PWR_MAX_DBM;
471 } else {
472 if (dbm < BLE_XCVR_TX_PWR_MIN_DBM) {
473 dbm = BLE_XCVR_TX_PWR_MIN_DBM;
474 }
475 }
476
477 g_ble_phy_data.phy_txpwr_dbm = dbm;
478
479 return 0;
480 }
481
482 /**
483 * ble phy txpwr round
484 *
485 * Get the rounded transmit output power (in dBm).
486 *
487 * @param dbm Power output in dBm.
488 *
489 * @return int Rounded power in dBm
490 */
ble_phy_txpower_round(int dbm)491 int ble_phy_txpower_round(int dbm)
492 {
493 /* "Rail" power level if outside supported range */
494 if (dbm > BLE_XCVR_TX_PWR_MAX_DBM) {
495 dbm = BLE_XCVR_TX_PWR_MAX_DBM;
496 } else {
497 if (dbm < BLE_XCVR_TX_PWR_MIN_DBM) {
498 dbm = BLE_XCVR_TX_PWR_MIN_DBM;
499 }
500 }
501
502 return dbm;
503 }
504
505 /**
506 * ble phy txpwr get
507 *
508 * Get the transmit power.
509 *
510 * @return int The current PHY transmit power, in dBm
511 */
512 int
ble_phy_txpwr_get(void)513 ble_phy_txpwr_get(void)
514 {
515 return g_ble_phy_data.phy_txpwr_dbm;
516 }
517
518 /**
519 * ble phy setchan
520 *
521 * Sets the logical frequency of the transceiver. The input parameter is the
522 * BLE channel index (0 to 39, inclusive). The NRF52 frequency register
523 * works like this: logical frequency = 2400 + FREQ (MHz).
524 *
525 * Thus, to get a logical frequency of 2402 MHz, you would program the
526 * FREQUENCY register to 2.
527 *
528 * @param chan This is the Data Channel Index or Advertising Channel index
529 *
530 * @return int 0: success; PHY error code otherwise
531 */
532 int
ble_phy_setchan(uint8_t chan,uint32_t access_addr,uint32_t crcinit)533 ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit)
534 {
535 assert(chan < BLE_PHY_NUM_CHANS);
536
537 /* Check for valid channel range */
538 if (chan >= BLE_PHY_NUM_CHANS) {
539 return BLE_PHY_ERR_INV_PARAM;
540 }
541
542 g_ble_phy_data.phy_access_address = access_addr;
543
544 g_ble_phy_data.phy_chan = chan;
545
546 return 0;
547 }
548
549 /**
550 * Disable the PHY. This will do the following:
551 * -> Turn off all phy interrupts.
552 * -> Disable internal shortcuts.
553 * -> Disable the radio.
554 * -> Sets phy state to idle.
555 */
556 void
ble_phy_disable(void)557 ble_phy_disable(void)
558 {
559 g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE;
560 }
561
562 /* Gets the current access address */
ble_phy_access_addr_get(void)563 uint32_t ble_phy_access_addr_get(void)
564 {
565 return g_ble_phy_data.phy_access_address;
566 }
567
568 /**
569 * Return the phy state
570 *
571 * @return int The current PHY state.
572 */
573 int
ble_phy_state_get(void)574 ble_phy_state_get(void)
575 {
576 return g_ble_phy_data.phy_state;
577 }
578
579 /**
580 * Called to see if a reception has started
581 *
582 * @return int
583 */
584 int
ble_phy_rx_started(void)585 ble_phy_rx_started(void)
586 {
587 return g_ble_phy_data.phy_rx_started;
588 }
589
590 /**
591 * Called to return the maximum data pdu payload length supported by the
592 * phy. For this chip, if encryption is enabled, the maximum payload is 27
593 * bytes.
594 *
595 * @return uint8_t Maximum data channel PDU payload size supported
596 */
597 uint8_t
ble_phy_max_data_pdu_pyld(void)598 ble_phy_max_data_pdu_pyld(void)
599 {
600 return BLE_LL_DATA_PDU_MAX_PYLD;
601 }
602
603 #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
604 void
ble_phy_resolv_list_enable(void)605 ble_phy_resolv_list_enable(void)
606 {
607 g_ble_phy_data.phy_privacy = 1;
608 }
609
610 void
ble_phy_resolv_list_disable(void)611 ble_phy_resolv_list_disable(void)
612 {
613 g_ble_phy_data.phy_privacy = 0;
614 }
615
616 /**
617 * Return the transceiver state
618 *
619 * @return int transceiver state.
620 */
621 uint8_t
ble_phy_xcvr_state_get(void)622 ble_phy_xcvr_state_get(void)
623 {
624 return g_ble_phy_data.phy_state;
625 }
626
627 #endif
628
629 void
ble_phy_wfr_enable(int txrx,uint8_t tx_phy_mode,uint32_t wfr_usecs)630 ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs)
631 {
632 }
633