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