xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/drivers/native/src/ble_phy.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 <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