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 "mcu/cmsis_nvic.h"
27*042d53a7SEvalZero #include "nimble/ble.h"
28*042d53a7SEvalZero #include "nimble/nimble_opt.h"
29*042d53a7SEvalZero #include "controller/ble_phy.h"
30*042d53a7SEvalZero #include "controller/ble_phy_trace.h"
31*042d53a7SEvalZero #include "controller/ble_ll.h"
32*042d53a7SEvalZero #include "nrfx.h"
33*042d53a7SEvalZero
34*042d53a7SEvalZero #if MYNEWT
35*042d53a7SEvalZero #include "mcu/nrf51_clock.h"
36*042d53a7SEvalZero #endif
37*042d53a7SEvalZero
38*042d53a7SEvalZero /* XXX: 4) Make sure RF is higher priority interrupt than schedule */
39*042d53a7SEvalZero
40*042d53a7SEvalZero /*
41*042d53a7SEvalZero * XXX: Maximum possible transmit time is 1 msec for a 60ppm crystal
42*042d53a7SEvalZero * and 16ms for a 30ppm crystal! We need to limit PDU size based on
43*042d53a7SEvalZero * crystal accuracy. Look at this in the spec.
44*042d53a7SEvalZero */
45*042d53a7SEvalZero
46*042d53a7SEvalZero /* XXX: private header file? */
47*042d53a7SEvalZero extern uint8_t g_nrf_num_irks;
48*042d53a7SEvalZero extern uint32_t g_nrf_irk_list[];
49*042d53a7SEvalZero
50*042d53a7SEvalZero /* To disable all radio interrupts */
51*042d53a7SEvalZero #define NRF_RADIO_IRQ_MASK_ALL (0x34FF)
52*042d53a7SEvalZero
53*042d53a7SEvalZero /*
54*042d53a7SEvalZero * We configure the nrf with a 1 byte S0 field, 8 bit length field, and
55*042d53a7SEvalZero * zero bit S1 field. The preamble is 8 bits long.
56*042d53a7SEvalZero */
57*042d53a7SEvalZero #define NRF_LFLEN_BITS (8)
58*042d53a7SEvalZero #define NRF_S0_LEN (1)
59*042d53a7SEvalZero
60*042d53a7SEvalZero /* Maximum length of frames */
61*042d53a7SEvalZero #define NRF_MAXLEN (255)
62*042d53a7SEvalZero #define NRF_BALEN (3) /* For base address of 3 bytes */
63*042d53a7SEvalZero
64*042d53a7SEvalZero /* Maximum tx power */
65*042d53a7SEvalZero #define NRF_TX_PWR_MAX_DBM (4)
66*042d53a7SEvalZero #define NRF_TX_PWR_MIN_DBM (-40)
67*042d53a7SEvalZero
68*042d53a7SEvalZero /* Max. encrypted payload length */
69*042d53a7SEvalZero #define NRF_MAX_ENCRYPTED_PYLD_LEN (27)
70*042d53a7SEvalZero #define NRF_ENC_HDR_SIZE (3)
71*042d53a7SEvalZero #define NRF_ENC_BUF_SIZE \
72*042d53a7SEvalZero (NRF_MAX_ENCRYPTED_PYLD_LEN + NRF_ENC_HDR_SIZE + BLE_LL_DATA_MIC_LEN)
73*042d53a7SEvalZero
74*042d53a7SEvalZero /* BLE PHY data structure */
75*042d53a7SEvalZero struct ble_phy_obj
76*042d53a7SEvalZero {
77*042d53a7SEvalZero uint8_t phy_stats_initialized;
78*042d53a7SEvalZero int8_t phy_txpwr_dbm;
79*042d53a7SEvalZero uint8_t phy_chan;
80*042d53a7SEvalZero uint8_t phy_state;
81*042d53a7SEvalZero uint8_t phy_transition;
82*042d53a7SEvalZero uint8_t phy_rx_started;
83*042d53a7SEvalZero uint8_t phy_encrypted;
84*042d53a7SEvalZero uint8_t phy_privacy;
85*042d53a7SEvalZero uint8_t phy_tx_pyld_len;
86*042d53a7SEvalZero uint8_t *rxdptr;
87*042d53a7SEvalZero uint32_t phy_aar_scratch;
88*042d53a7SEvalZero uint32_t phy_access_address;
89*042d53a7SEvalZero struct ble_mbuf_hdr rxhdr;
90*042d53a7SEvalZero void *txend_arg;
91*042d53a7SEvalZero ble_phy_tx_end_func txend_cb;
92*042d53a7SEvalZero uint32_t phy_start_cputime;
93*042d53a7SEvalZero };
94*042d53a7SEvalZero struct ble_phy_obj g_ble_phy_data;
95*042d53a7SEvalZero
96*042d53a7SEvalZero /* XXX: if 27 byte packets desired we can make this smaller */
97*042d53a7SEvalZero /* Global transmit/receive buffer */
98*042d53a7SEvalZero static uint32_t g_ble_phy_tx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4];
99*042d53a7SEvalZero static uint32_t g_ble_phy_rx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4];
100*042d53a7SEvalZero
101*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
102*042d53a7SEvalZero /* Make sure word-aligned for faster copies */
103*042d53a7SEvalZero static uint32_t g_ble_phy_enc_buf[(NRF_ENC_BUF_SIZE + 3) / 4];
104*042d53a7SEvalZero #endif
105*042d53a7SEvalZero
106*042d53a7SEvalZero /* RF center frequency for each channel index (offset from 2400 MHz) */
107*042d53a7SEvalZero static const uint8_t g_ble_phy_chan_freq[BLE_PHY_NUM_CHANS] = {
108*042d53a7SEvalZero 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, /* 0-9 */
109*042d53a7SEvalZero 24, 28, 30, 32, 34, 36, 38, 40, 42, 44, /* 10-19 */
110*042d53a7SEvalZero 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, /* 20-29 */
111*042d53a7SEvalZero 66, 68, 70, 72, 74, 76, 78, 2, 26, 80, /* 30-39 */
112*042d53a7SEvalZero };
113*042d53a7SEvalZero
114*042d53a7SEvalZero /* Statistics */
115*042d53a7SEvalZero STATS_SECT_START(ble_phy_stats)
116*042d53a7SEvalZero STATS_SECT_ENTRY(phy_isrs)
117*042d53a7SEvalZero STATS_SECT_ENTRY(tx_good)
118*042d53a7SEvalZero STATS_SECT_ENTRY(tx_fail)
119*042d53a7SEvalZero STATS_SECT_ENTRY(tx_late)
120*042d53a7SEvalZero STATS_SECT_ENTRY(tx_bytes)
121*042d53a7SEvalZero STATS_SECT_ENTRY(rx_starts)
122*042d53a7SEvalZero STATS_SECT_ENTRY(rx_aborts)
123*042d53a7SEvalZero STATS_SECT_ENTRY(rx_valid)
124*042d53a7SEvalZero STATS_SECT_ENTRY(rx_crc_err)
125*042d53a7SEvalZero STATS_SECT_ENTRY(rx_late)
126*042d53a7SEvalZero STATS_SECT_ENTRY(radio_state_errs)
127*042d53a7SEvalZero STATS_SECT_ENTRY(rx_hw_err)
128*042d53a7SEvalZero STATS_SECT_ENTRY(tx_hw_err)
129*042d53a7SEvalZero STATS_SECT_END
130*042d53a7SEvalZero STATS_SECT_DECL(ble_phy_stats) ble_phy_stats;
131*042d53a7SEvalZero
132*042d53a7SEvalZero STATS_NAME_START(ble_phy_stats)
133*042d53a7SEvalZero STATS_NAME(ble_phy_stats, phy_isrs)
134*042d53a7SEvalZero STATS_NAME(ble_phy_stats, tx_good)
135*042d53a7SEvalZero STATS_NAME(ble_phy_stats, tx_fail)
136*042d53a7SEvalZero STATS_NAME(ble_phy_stats, tx_late)
137*042d53a7SEvalZero STATS_NAME(ble_phy_stats, tx_bytes)
138*042d53a7SEvalZero STATS_NAME(ble_phy_stats, rx_starts)
139*042d53a7SEvalZero STATS_NAME(ble_phy_stats, rx_aborts)
140*042d53a7SEvalZero STATS_NAME(ble_phy_stats, rx_valid)
141*042d53a7SEvalZero STATS_NAME(ble_phy_stats, rx_crc_err)
142*042d53a7SEvalZero STATS_NAME(ble_phy_stats, rx_late)
143*042d53a7SEvalZero STATS_NAME(ble_phy_stats, radio_state_errs)
144*042d53a7SEvalZero STATS_NAME(ble_phy_stats, rx_hw_err)
145*042d53a7SEvalZero STATS_NAME(ble_phy_stats, tx_hw_err)
146*042d53a7SEvalZero STATS_NAME_END(ble_phy_stats)
147*042d53a7SEvalZero
148*042d53a7SEvalZero /*
149*042d53a7SEvalZero * NOTE:
150*042d53a7SEvalZero * Tested the following to see what would happen:
151*042d53a7SEvalZero * -> NVIC has radio irq enabled (interrupt # 1, mask 0x2).
152*042d53a7SEvalZero * -> Set up nrf to receive. Clear ADDRESS event register.
153*042d53a7SEvalZero * -> Enable ADDRESS interrupt on nrf5 by writing to INTENSET.
154*042d53a7SEvalZero * -> Enable RX.
155*042d53a7SEvalZero * -> Disable interrupts globally using OS_ENTER_CRITICAL().
156*042d53a7SEvalZero * -> Wait until a packet is received and the ADDRESS event occurs.
157*042d53a7SEvalZero * -> Call ble_phy_disable().
158*042d53a7SEvalZero *
159*042d53a7SEvalZero * At this point I wanted to see the state of the cortex NVIC. The IRQ
160*042d53a7SEvalZero * pending bit was TRUE for the radio interrupt (as expected) as we never
161*042d53a7SEvalZero * serviced the radio interrupt (interrupts were disabled).
162*042d53a7SEvalZero *
163*042d53a7SEvalZero * What was unexpected was this: without clearing the pending IRQ in the NVIC,
164*042d53a7SEvalZero * when radio interrupts were re-enabled (address event bit in INTENSET set to
165*042d53a7SEvalZero * 1) and the radio ADDRESS event register read 1 (it was never cleared after
166*042d53a7SEvalZero * the first address event), the radio did not enter the ISR! I would have
167*042d53a7SEvalZero * expected that if the following were true, an interrupt would occur:
168*042d53a7SEvalZero * -> NVIC ISER bit set to TRUE
169*042d53a7SEvalZero * -> NVIC ISPR bit reads TRUE, meaning interrupt is pending.
170*042d53a7SEvalZero * -> Radio peripheral interrupts are enabled for some event (or events).
171*042d53a7SEvalZero * -> Corresponding event register(s) in radio peripheral read 1.
172*042d53a7SEvalZero *
173*042d53a7SEvalZero * Not sure what the end result of all this is. We will clear the pending
174*042d53a7SEvalZero * bit in the NVIC just to be sure when we disable the PHY.
175*042d53a7SEvalZero */
176*042d53a7SEvalZero
177*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
178*042d53a7SEvalZero /* Per nordic, the number of bytes needed for scratch is 16 + MAX_PKT_SIZE. */
179*042d53a7SEvalZero #define NRF_ENC_SCRATCH_WORDS (((NRF_MAX_ENCRYPTED_PYLD_LEN + 16) + 3) / 4)
180*042d53a7SEvalZero
181*042d53a7SEvalZero uint32_t g_nrf_encrypt_scratchpad[NRF_ENC_SCRATCH_WORDS];
182*042d53a7SEvalZero
183*042d53a7SEvalZero struct nrf_ccm_data
184*042d53a7SEvalZero {
185*042d53a7SEvalZero uint8_t key[16];
186*042d53a7SEvalZero uint64_t pkt_counter;
187*042d53a7SEvalZero uint8_t dir_bit;
188*042d53a7SEvalZero uint8_t iv[8];
189*042d53a7SEvalZero } __attribute__((packed));
190*042d53a7SEvalZero
191*042d53a7SEvalZero struct nrf_ccm_data g_nrf_ccm_data;
192*042d53a7SEvalZero #endif
193*042d53a7SEvalZero
194*042d53a7SEvalZero /**
195*042d53a7SEvalZero * Copies the data from the phy receive buffer into a mbuf chain.
196*042d53a7SEvalZero *
197*042d53a7SEvalZero * @param dptr Pointer to receive buffer
198*042d53a7SEvalZero * @param rxpdu Pointer to already allocated mbuf chain
199*042d53a7SEvalZero *
200*042d53a7SEvalZero * NOTE: the packet header already has the total mbuf length in it. The
201*042d53a7SEvalZero * lengths of the individual mbufs are not set prior to calling.
202*042d53a7SEvalZero *
203*042d53a7SEvalZero */
204*042d53a7SEvalZero void
ble_phy_rxpdu_copy(uint8_t * dptr,struct os_mbuf * rxpdu)205*042d53a7SEvalZero ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu)
206*042d53a7SEvalZero {
207*042d53a7SEvalZero uint16_t rem_bytes;
208*042d53a7SEvalZero uint16_t mb_bytes;
209*042d53a7SEvalZero uint16_t copylen;
210*042d53a7SEvalZero uint32_t *dst;
211*042d53a7SEvalZero uint32_t *src;
212*042d53a7SEvalZero struct os_mbuf *m;
213*042d53a7SEvalZero struct ble_mbuf_hdr *ble_hdr;
214*042d53a7SEvalZero struct os_mbuf_pkthdr *pkthdr;
215*042d53a7SEvalZero
216*042d53a7SEvalZero /* Better be aligned */
217*042d53a7SEvalZero assert(((uint32_t)dptr & 3) == 0);
218*042d53a7SEvalZero
219*042d53a7SEvalZero pkthdr = OS_MBUF_PKTHDR(rxpdu);
220*042d53a7SEvalZero rem_bytes = pkthdr->omp_len;
221*042d53a7SEvalZero
222*042d53a7SEvalZero /* Fill in the mbuf pkthdr first. */
223*042d53a7SEvalZero dst = (uint32_t *)(rxpdu->om_data);
224*042d53a7SEvalZero src = (uint32_t *)dptr;
225*042d53a7SEvalZero
226*042d53a7SEvalZero mb_bytes = (rxpdu->om_omp->omp_databuf_len - rxpdu->om_pkthdr_len - 4);
227*042d53a7SEvalZero copylen = min(mb_bytes, rem_bytes);
228*042d53a7SEvalZero copylen &= 0xFFFC;
229*042d53a7SEvalZero rem_bytes -= copylen;
230*042d53a7SEvalZero mb_bytes -= copylen;
231*042d53a7SEvalZero rxpdu->om_len = copylen;
232*042d53a7SEvalZero while (copylen > 0) {
233*042d53a7SEvalZero *dst = *src;
234*042d53a7SEvalZero ++dst;
235*042d53a7SEvalZero ++src;
236*042d53a7SEvalZero copylen -= 4;
237*042d53a7SEvalZero }
238*042d53a7SEvalZero
239*042d53a7SEvalZero /* Copy remaining bytes */
240*042d53a7SEvalZero m = rxpdu;
241*042d53a7SEvalZero while (rem_bytes > 0) {
242*042d53a7SEvalZero /* If there are enough bytes in the mbuf, copy them and leave */
243*042d53a7SEvalZero if (rem_bytes <= mb_bytes) {
244*042d53a7SEvalZero memcpy(m->om_data + m->om_len, src, rem_bytes);
245*042d53a7SEvalZero m->om_len += rem_bytes;
246*042d53a7SEvalZero break;
247*042d53a7SEvalZero }
248*042d53a7SEvalZero
249*042d53a7SEvalZero m = SLIST_NEXT(m, om_next);
250*042d53a7SEvalZero assert(m != NULL);
251*042d53a7SEvalZero
252*042d53a7SEvalZero mb_bytes = m->om_omp->omp_databuf_len;
253*042d53a7SEvalZero copylen = min(mb_bytes, rem_bytes);
254*042d53a7SEvalZero copylen &= 0xFFFC;
255*042d53a7SEvalZero rem_bytes -= copylen;
256*042d53a7SEvalZero mb_bytes -= copylen;
257*042d53a7SEvalZero m->om_len = copylen;
258*042d53a7SEvalZero dst = (uint32_t *)m->om_data;
259*042d53a7SEvalZero while (copylen > 0) {
260*042d53a7SEvalZero *dst = *src;
261*042d53a7SEvalZero ++dst;
262*042d53a7SEvalZero ++src;
263*042d53a7SEvalZero copylen -= 4;
264*042d53a7SEvalZero }
265*042d53a7SEvalZero }
266*042d53a7SEvalZero
267*042d53a7SEvalZero /* Copy ble header */
268*042d53a7SEvalZero ble_hdr = BLE_MBUF_HDR_PTR(rxpdu);
269*042d53a7SEvalZero memcpy(ble_hdr, &g_ble_phy_data.rxhdr, sizeof(struct ble_mbuf_hdr));
270*042d53a7SEvalZero }
271*042d53a7SEvalZero
272*042d53a7SEvalZero /**
273*042d53a7SEvalZero * Called when we want to wait if the radio is in either the rx or tx
274*042d53a7SEvalZero * disable states. We want to wait until that state is over before doing
275*042d53a7SEvalZero * anything to the radio
276*042d53a7SEvalZero */
277*042d53a7SEvalZero static void
nrf_wait_disabled(void)278*042d53a7SEvalZero nrf_wait_disabled(void)
279*042d53a7SEvalZero {
280*042d53a7SEvalZero uint32_t state;
281*042d53a7SEvalZero
282*042d53a7SEvalZero /*
283*042d53a7SEvalZero * RX and TX states have the same values except for 3rd bit (0=RX, 1=TX) so
284*042d53a7SEvalZero * we use RX symbols only.
285*042d53a7SEvalZero */
286*042d53a7SEvalZero state = NRF_RADIO->STATE & 0x07;
287*042d53a7SEvalZero
288*042d53a7SEvalZero if (state != RADIO_STATE_STATE_Disabled) {
289*042d53a7SEvalZero /* If PHY is in idle state for whatever reason, disable it now */
290*042d53a7SEvalZero if (state == RADIO_STATE_STATE_RxIdle) {
291*042d53a7SEvalZero NRF_RADIO->TASKS_DISABLE = 1;
292*042d53a7SEvalZero STATS_INC(ble_phy_stats, radio_state_errs);
293*042d53a7SEvalZero }
294*042d53a7SEvalZero
295*042d53a7SEvalZero if (state == RADIO_STATE_STATE_RxDisable) {
296*042d53a7SEvalZero /* This will end within a short time (6 usecs). Just poll */
297*042d53a7SEvalZero while (NRF_RADIO->STATE == state) {
298*042d53a7SEvalZero /* If this fails, something is really wrong. Should last
299*042d53a7SEvalZero * no more than 6 usecs */
300*042d53a7SEvalZero }
301*042d53a7SEvalZero }
302*042d53a7SEvalZero }
303*042d53a7SEvalZero }
304*042d53a7SEvalZero
305*042d53a7SEvalZero /**
306*042d53a7SEvalZero *
307*042d53a7SEvalZero *
308*042d53a7SEvalZero */
309*042d53a7SEvalZero int
ble_phy_set_start_time(uint32_t cputime,uint8_t rem_usecs)310*042d53a7SEvalZero ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs)
311*042d53a7SEvalZero {
312*042d53a7SEvalZero uint32_t next_cc;
313*042d53a7SEvalZero uint32_t cur_cc;
314*042d53a7SEvalZero uint32_t cntr;
315*042d53a7SEvalZero uint32_t delta;
316*042d53a7SEvalZero
317*042d53a7SEvalZero /*
318*042d53a7SEvalZero * XXX: The TXEN time is 140 usecs but there may be additional delays
319*042d53a7SEvalZero * Need to look at this.
320*042d53a7SEvalZero */
321*042d53a7SEvalZero
322*042d53a7SEvalZero /*
323*042d53a7SEvalZero * With the 32.768 kHz crystal, we may need to adjust the RTC compare
324*042d53a7SEvalZero * value by 1 tick due to the time it takes for TXEN. The code uses a 5 RTC
325*042d53a7SEvalZero * tick offset, which is 152.5 usecs. The TXEN time is 140 usecs. This
326*042d53a7SEvalZero * means that with a remainder of 0, TIMER0 should be set to 12 or 13 (as
327*042d53a7SEvalZero * TIMER0 counts at 1MHz). A remainder of 19 or more we will need to add
328*042d53a7SEvalZero * 1 tick. We dont need to add 1 tick per se, but it does give us slightly
329*042d53a7SEvalZero * more time and thus less of a chance to miss a tick. Another note: we
330*042d53a7SEvalZero * cant set TIMER0 CC to 0 as the compare wont occur; it must be 1 or more.
331*042d53a7SEvalZero * This is why we subtract 18 (as opposed to 19) as rem_uses will be >= 1.
332*042d53a7SEvalZero */
333*042d53a7SEvalZero if (rem_usecs <= 18) {
334*042d53a7SEvalZero cputime -= 5;
335*042d53a7SEvalZero rem_usecs += 12;
336*042d53a7SEvalZero } else {
337*042d53a7SEvalZero cputime -= 4;
338*042d53a7SEvalZero rem_usecs -= 18;
339*042d53a7SEvalZero }
340*042d53a7SEvalZero
341*042d53a7SEvalZero /*
342*042d53a7SEvalZero * Can we set the RTC compare to start TIMER0? We can do it if:
343*042d53a7SEvalZero * a) Current compare value is not N+1 or N+2 ticks from current
344*042d53a7SEvalZero * counter.
345*042d53a7SEvalZero * b) The value we want to set is not at least N+2 from current
346*042d53a7SEvalZero * counter.
347*042d53a7SEvalZero *
348*042d53a7SEvalZero * NOTE: since the counter can tick 1 while we do these calculations we
349*042d53a7SEvalZero * need to account for it.
350*042d53a7SEvalZero */
351*042d53a7SEvalZero next_cc = cputime & 0xffffff;
352*042d53a7SEvalZero cur_cc = NRF_RTC0->CC[0];
353*042d53a7SEvalZero cntr = NRF_RTC0->COUNTER;
354*042d53a7SEvalZero
355*042d53a7SEvalZero delta = (cur_cc - cntr) & 0xffffff;
356*042d53a7SEvalZero if ((delta <= 3) && (delta != 0)) {
357*042d53a7SEvalZero return -1;
358*042d53a7SEvalZero }
359*042d53a7SEvalZero delta = (next_cc - cntr) & 0xffffff;
360*042d53a7SEvalZero if ((delta & 0x800000) || (delta < 3)) {
361*042d53a7SEvalZero return -1;
362*042d53a7SEvalZero }
363*042d53a7SEvalZero
364*042d53a7SEvalZero /* Clear and set TIMER0 to fire off at proper time */
365*042d53a7SEvalZero NRF_TIMER0->TASKS_CLEAR = 1;
366*042d53a7SEvalZero NRF_TIMER0->CC[0] = rem_usecs;
367*042d53a7SEvalZero NRF_TIMER0->EVENTS_COMPARE[0] = 0;
368*042d53a7SEvalZero
369*042d53a7SEvalZero /* Set RTC compare to start TIMER0 */
370*042d53a7SEvalZero NRF_RTC0->EVENTS_COMPARE[0] = 0;
371*042d53a7SEvalZero NRF_RTC0->CC[0] = next_cc;
372*042d53a7SEvalZero NRF_RTC0->EVTENSET = RTC_EVTENSET_COMPARE0_Msk;
373*042d53a7SEvalZero
374*042d53a7SEvalZero /* Enable PPI */
375*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH31_Msk;
376*042d53a7SEvalZero
377*042d53a7SEvalZero /* Store the cputime at which we set the RTC */
378*042d53a7SEvalZero g_ble_phy_data.phy_start_cputime = cputime;
379*042d53a7SEvalZero
380*042d53a7SEvalZero return 0;
381*042d53a7SEvalZero }
382*042d53a7SEvalZero
383*042d53a7SEvalZero /**
384*042d53a7SEvalZero * Function is used to set PPI so that we can time out waiting for a reception
385*042d53a7SEvalZero * to occur. This happens for two reasons: we have sent a packet and we are
386*042d53a7SEvalZero * waiting for a respons (txrx should be set to ENABLE_TXRX) or we are
387*042d53a7SEvalZero * starting a connection event and we are a slave and we are waiting for the
388*042d53a7SEvalZero * master to send us a packet (txrx should be set to ENABLE_RX).
389*042d53a7SEvalZero *
390*042d53a7SEvalZero * NOTE: when waiting for a txrx turn-around, wfr_usecs is not used as there
391*042d53a7SEvalZero * is no additional time to wait; we know when we should receive the address of
392*042d53a7SEvalZero * the received frame.
393*042d53a7SEvalZero *
394*042d53a7SEvalZero * @param txrx Flag denoting if this wfr is a txrx turn-around or not.
395*042d53a7SEvalZero * @param tx_phy_mode phy mode for last TX (not used on nRF51)
396*042d53a7SEvalZero * @param wfr_usecs Amount of usecs to wait.
397*042d53a7SEvalZero */
398*042d53a7SEvalZero void
ble_phy_wfr_enable(int txrx,uint8_t tx_phy_mode,uint32_t wfr_usecs)399*042d53a7SEvalZero ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs)
400*042d53a7SEvalZero {
401*042d53a7SEvalZero uint32_t end_time;
402*042d53a7SEvalZero
403*042d53a7SEvalZero if (txrx == BLE_PHY_WFR_ENABLE_TXRX) {
404*042d53a7SEvalZero /*
405*042d53a7SEvalZero * Timeout occurs an IFS time plus time it takes to receive address
406*042d53a7SEvalZero * from the transmit end. We add additional time to make sure the
407*042d53a7SEvalZero * address event comes before the compare. Note that transmit end
408*042d53a7SEvalZero * is captured in CC[2]. I just made up the 16 usecs I add here.
409*042d53a7SEvalZero */
410*042d53a7SEvalZero end_time = NRF_TIMER0->CC[2] + BLE_LL_IFS +
411*042d53a7SEvalZero ble_phy_mode_pdu_start_off(BLE_PHY_MODE_1M) + 16;
412*042d53a7SEvalZero } else {
413*042d53a7SEvalZero /* CC[0] is set to when RXEN occurs. */
414*042d53a7SEvalZero end_time = NRF_TIMER0->CC[0] + XCVR_RX_START_DELAY_USECS + wfr_usecs +
415*042d53a7SEvalZero ble_phy_mode_pdu_start_off(BLE_PHY_MODE_1M) + BLE_LL_JITTER_USECS;
416*042d53a7SEvalZero }
417*042d53a7SEvalZero
418*042d53a7SEvalZero /* wfr_secs is the time from rxen until timeout */
419*042d53a7SEvalZero NRF_TIMER0->CC[3] = end_time;
420*042d53a7SEvalZero NRF_TIMER0->EVENTS_COMPARE[3] = 0;
421*042d53a7SEvalZero
422*042d53a7SEvalZero /* Enable wait for response PPI */
423*042d53a7SEvalZero NRF_PPI->CHENSET = (PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk);
424*042d53a7SEvalZero
425*042d53a7SEvalZero /* Enable the disabled interrupt so we time out on events compare */
426*042d53a7SEvalZero NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk;
427*042d53a7SEvalZero }
428*042d53a7SEvalZero
429*042d53a7SEvalZero /**
430*042d53a7SEvalZero * Setup transceiver for receive.
431*042d53a7SEvalZero */
432*042d53a7SEvalZero static void
ble_phy_rx_xcvr_setup(void)433*042d53a7SEvalZero ble_phy_rx_xcvr_setup(void)
434*042d53a7SEvalZero {
435*042d53a7SEvalZero uint8_t *dptr;
436*042d53a7SEvalZero
437*042d53a7SEvalZero dptr = (uint8_t *)&g_ble_phy_rx_buf[0];
438*042d53a7SEvalZero
439*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
440*042d53a7SEvalZero if (g_ble_phy_data.phy_encrypted) {
441*042d53a7SEvalZero dptr += 3;
442*042d53a7SEvalZero NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_enc_buf[0];
443*042d53a7SEvalZero NRF_CCM->INPTR = (uint32_t)&g_ble_phy_enc_buf[0];
444*042d53a7SEvalZero NRF_CCM->OUTPTR = (uint32_t)dptr;
445*042d53a7SEvalZero NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0];
446*042d53a7SEvalZero NRF_CCM->MODE = CCM_MODE_MODE_Decryption;
447*042d53a7SEvalZero NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data;
448*042d53a7SEvalZero NRF_CCM->SHORTS = 0;
449*042d53a7SEvalZero NRF_CCM->EVENTS_ERROR = 0;
450*042d53a7SEvalZero NRF_CCM->EVENTS_ENDCRYPT = 0;
451*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH24_Msk | PPI_CHEN_CH25_Msk;
452*042d53a7SEvalZero } else {
453*042d53a7SEvalZero NRF_RADIO->PACKETPTR = (uint32_t)dptr;
454*042d53a7SEvalZero }
455*042d53a7SEvalZero #else
456*042d53a7SEvalZero NRF_RADIO->PACKETPTR = (uint32_t)dptr;
457*042d53a7SEvalZero #endif
458*042d53a7SEvalZero
459*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
460*042d53a7SEvalZero if (g_ble_phy_data.phy_privacy) {
461*042d53a7SEvalZero dptr += 3;
462*042d53a7SEvalZero NRF_RADIO->PACKETPTR = (uint32_t)dptr;
463*042d53a7SEvalZero NRF_RADIO->PCNF0 = (6 << RADIO_PCNF0_LFLEN_Pos) |
464*042d53a7SEvalZero (2 << RADIO_PCNF0_S1LEN_Pos) |
465*042d53a7SEvalZero (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos);
466*042d53a7SEvalZero NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Enabled;
467*042d53a7SEvalZero NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
468*042d53a7SEvalZero NRF_AAR->SCRATCHPTR = (uint32_t)&g_ble_phy_data.phy_aar_scratch;
469*042d53a7SEvalZero NRF_AAR->EVENTS_END = 0;
470*042d53a7SEvalZero NRF_AAR->EVENTS_RESOLVED = 0;
471*042d53a7SEvalZero NRF_AAR->EVENTS_NOTRESOLVED = 0;
472*042d53a7SEvalZero } else {
473*042d53a7SEvalZero if (g_ble_phy_data.phy_encrypted == 0) {
474*042d53a7SEvalZero NRF_RADIO->PCNF0 = (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) |
475*042d53a7SEvalZero (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos);
476*042d53a7SEvalZero /* XXX: do I only need to do this once? Figure out what I can do
477*042d53a7SEvalZero once. */
478*042d53a7SEvalZero NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled;
479*042d53a7SEvalZero }
480*042d53a7SEvalZero }
481*042d53a7SEvalZero #endif
482*042d53a7SEvalZero
483*042d53a7SEvalZero /* Turn off trigger TXEN on output compare match and AAR on bcmatch */
484*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk | PPI_CHEN_CH23_Msk;
485*042d53a7SEvalZero
486*042d53a7SEvalZero /* Reset the rx started flag. Used for the wait for response */
487*042d53a7SEvalZero g_ble_phy_data.phy_rx_started = 0;
488*042d53a7SEvalZero g_ble_phy_data.phy_state = BLE_PHY_STATE_RX;
489*042d53a7SEvalZero g_ble_phy_data.rxdptr = dptr;
490*042d53a7SEvalZero
491*042d53a7SEvalZero /* I want to know when 1st byte received (after address) */
492*042d53a7SEvalZero NRF_RADIO->BCC = 8; /* in bits */
493*042d53a7SEvalZero NRF_RADIO->EVENTS_ADDRESS = 0;
494*042d53a7SEvalZero NRF_RADIO->EVENTS_DEVMATCH = 0;
495*042d53a7SEvalZero NRF_RADIO->EVENTS_BCMATCH = 0;
496*042d53a7SEvalZero NRF_RADIO->EVENTS_RSSIEND = 0;
497*042d53a7SEvalZero NRF_RADIO->SHORTS = RADIO_SHORTS_END_DISABLE_Msk |
498*042d53a7SEvalZero RADIO_SHORTS_READY_START_Msk |
499*042d53a7SEvalZero RADIO_SHORTS_DISABLED_TXEN_Msk |
500*042d53a7SEvalZero RADIO_SHORTS_ADDRESS_BCSTART_Msk |
501*042d53a7SEvalZero RADIO_SHORTS_ADDRESS_RSSISTART_Msk |
502*042d53a7SEvalZero RADIO_SHORTS_DISABLED_RSSISTOP_Msk;
503*042d53a7SEvalZero
504*042d53a7SEvalZero NRF_RADIO->INTENSET = RADIO_INTENSET_ADDRESS_Msk;
505*042d53a7SEvalZero }
506*042d53a7SEvalZero
507*042d53a7SEvalZero /**
508*042d53a7SEvalZero * Called from interrupt context when the transmit ends
509*042d53a7SEvalZero *
510*042d53a7SEvalZero */
511*042d53a7SEvalZero static void
ble_phy_tx_end_isr(void)512*042d53a7SEvalZero ble_phy_tx_end_isr(void)
513*042d53a7SEvalZero {
514*042d53a7SEvalZero uint8_t was_encrypted;
515*042d53a7SEvalZero uint8_t transition;
516*042d53a7SEvalZero uint8_t txlen;
517*042d53a7SEvalZero uint32_t wfr_time;
518*042d53a7SEvalZero
519*042d53a7SEvalZero /* If this transmission was encrypted we need to remember it */
520*042d53a7SEvalZero was_encrypted = g_ble_phy_data.phy_encrypted;
521*042d53a7SEvalZero (void)was_encrypted;
522*042d53a7SEvalZero
523*042d53a7SEvalZero /* Better be in TX state! */
524*042d53a7SEvalZero assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX);
525*042d53a7SEvalZero
526*042d53a7SEvalZero /* Clear events and clear interrupt on disabled event */
527*042d53a7SEvalZero NRF_RADIO->EVENTS_DISABLED = 0;
528*042d53a7SEvalZero NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk;
529*042d53a7SEvalZero NRF_RADIO->EVENTS_END = 0;
530*042d53a7SEvalZero wfr_time = NRF_RADIO->SHORTS;
531*042d53a7SEvalZero (void)wfr_time;
532*042d53a7SEvalZero
533*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
534*042d53a7SEvalZero /*
535*042d53a7SEvalZero * XXX: not sure what to do. We had a HW error during transmission.
536*042d53a7SEvalZero * For now I just count a stat but continue on like all is good.
537*042d53a7SEvalZero */
538*042d53a7SEvalZero if (was_encrypted) {
539*042d53a7SEvalZero if (NRF_CCM->EVENTS_ERROR) {
540*042d53a7SEvalZero STATS_INC(ble_phy_stats, tx_hw_err);
541*042d53a7SEvalZero NRF_CCM->EVENTS_ERROR = 0;
542*042d53a7SEvalZero }
543*042d53a7SEvalZero }
544*042d53a7SEvalZero #endif
545*042d53a7SEvalZero
546*042d53a7SEvalZero /* Call transmit end callback */
547*042d53a7SEvalZero if (g_ble_phy_data.txend_cb) {
548*042d53a7SEvalZero g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg);
549*042d53a7SEvalZero }
550*042d53a7SEvalZero
551*042d53a7SEvalZero transition = g_ble_phy_data.phy_transition;
552*042d53a7SEvalZero if (transition == BLE_PHY_TRANSITION_TX_RX) {
553*042d53a7SEvalZero /* Packet pointer needs to be reset. */
554*042d53a7SEvalZero ble_phy_rx_xcvr_setup();
555*042d53a7SEvalZero
556*042d53a7SEvalZero /*
557*042d53a7SEvalZero * Enable the wait for response timer. Note that cc #1 on
558*042d53a7SEvalZero * timer 0 contains the transmit start time
559*042d53a7SEvalZero */
560*042d53a7SEvalZero txlen = g_ble_phy_data.phy_tx_pyld_len;
561*042d53a7SEvalZero if (txlen && was_encrypted) {
562*042d53a7SEvalZero txlen += BLE_LL_DATA_MIC_LEN;
563*042d53a7SEvalZero }
564*042d53a7SEvalZero ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_TXRX, 0, 0);
565*042d53a7SEvalZero } else {
566*042d53a7SEvalZero /*
567*042d53a7SEvalZero * XXX: not sure we need to stop the timer here all the time. Or that
568*042d53a7SEvalZero * it should be stopped here.
569*042d53a7SEvalZero */
570*042d53a7SEvalZero NRF_TIMER0->TASKS_STOP = 1;
571*042d53a7SEvalZero NRF_TIMER0->TASKS_SHUTDOWN = 1;
572*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk |
573*042d53a7SEvalZero PPI_CHEN_CH20_Msk | PPI_CHEN_CH31_Msk;
574*042d53a7SEvalZero assert(transition == BLE_PHY_TRANSITION_NONE);
575*042d53a7SEvalZero }
576*042d53a7SEvalZero }
577*042d53a7SEvalZero
578*042d53a7SEvalZero static void
ble_phy_rx_end_isr(void)579*042d53a7SEvalZero ble_phy_rx_end_isr(void)
580*042d53a7SEvalZero {
581*042d53a7SEvalZero int rc;
582*042d53a7SEvalZero uint8_t *dptr;
583*042d53a7SEvalZero uint8_t crcok;
584*042d53a7SEvalZero struct ble_mbuf_hdr *ble_hdr;
585*042d53a7SEvalZero
586*042d53a7SEvalZero /* Clear events and clear interrupt */
587*042d53a7SEvalZero NRF_RADIO->EVENTS_END = 0;
588*042d53a7SEvalZero NRF_RADIO->INTENCLR = RADIO_INTENCLR_END_Msk;
589*042d53a7SEvalZero
590*042d53a7SEvalZero /* Disable automatic RXEN */
591*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
592*042d53a7SEvalZero
593*042d53a7SEvalZero /* Set RSSI and CRC status flag in header */
594*042d53a7SEvalZero ble_hdr = &g_ble_phy_data.rxhdr;
595*042d53a7SEvalZero assert(NRF_RADIO->EVENTS_RSSIEND != 0);
596*042d53a7SEvalZero ble_hdr->rxinfo.rssi = -1 * NRF_RADIO->RSSISAMPLE;
597*042d53a7SEvalZero
598*042d53a7SEvalZero dptr = g_ble_phy_data.rxdptr;
599*042d53a7SEvalZero
600*042d53a7SEvalZero /* Count PHY crc errors and valid packets */
601*042d53a7SEvalZero crcok = (uint8_t)NRF_RADIO->CRCSTATUS;
602*042d53a7SEvalZero if (!crcok) {
603*042d53a7SEvalZero STATS_INC(ble_phy_stats, rx_crc_err);
604*042d53a7SEvalZero } else {
605*042d53a7SEvalZero STATS_INC(ble_phy_stats, rx_valid);
606*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CRC_OK;
607*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
608*042d53a7SEvalZero if (g_ble_phy_data.phy_encrypted) {
609*042d53a7SEvalZero /* Only set MIC failure flag if frame is not zero length */
610*042d53a7SEvalZero if ((dptr[1] != 0) && (NRF_CCM->MICSTATUS == 0)) {
611*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_MIC_FAILURE;
612*042d53a7SEvalZero }
613*042d53a7SEvalZero
614*042d53a7SEvalZero /*
615*042d53a7SEvalZero * XXX: not sure how to deal with this. This should not
616*042d53a7SEvalZero * be a MIC failure but we should not hand it up. I guess
617*042d53a7SEvalZero * this is just some form of rx error and that is how we
618*042d53a7SEvalZero * handle it? For now, just set CRC error flags
619*042d53a7SEvalZero */
620*042d53a7SEvalZero if (NRF_CCM->EVENTS_ERROR) {
621*042d53a7SEvalZero STATS_INC(ble_phy_stats, rx_hw_err);
622*042d53a7SEvalZero ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK;
623*042d53a7SEvalZero }
624*042d53a7SEvalZero
625*042d53a7SEvalZero /*
626*042d53a7SEvalZero * XXX: This is a total hack work-around for now but I dont
627*042d53a7SEvalZero * know what else to do. If ENDCRYPT is not set and we are
628*042d53a7SEvalZero * encrypted we need to not trust this frame and drop it.
629*042d53a7SEvalZero */
630*042d53a7SEvalZero if (NRF_CCM->EVENTS_ENDCRYPT == 0) {
631*042d53a7SEvalZero STATS_INC(ble_phy_stats, rx_hw_err);
632*042d53a7SEvalZero ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK;
633*042d53a7SEvalZero }
634*042d53a7SEvalZero }
635*042d53a7SEvalZero #endif
636*042d53a7SEvalZero }
637*042d53a7SEvalZero
638*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
639*042d53a7SEvalZero if (g_ble_phy_data.phy_encrypted || g_ble_phy_data.phy_privacy) {
640*042d53a7SEvalZero /*
641*042d53a7SEvalZero * XXX: This is a horrible ugly hack to deal with the RAM S1 byte.
642*042d53a7SEvalZero * This should get fixed as we should not be handing up the header
643*042d53a7SEvalZero * and length as part of the pdu.
644*042d53a7SEvalZero */
645*042d53a7SEvalZero dptr[2] = dptr[1];
646*042d53a7SEvalZero dptr[1] = dptr[0];
647*042d53a7SEvalZero ++dptr;
648*042d53a7SEvalZero }
649*042d53a7SEvalZero #endif
650*042d53a7SEvalZero rc = ble_ll_rx_end(dptr, ble_hdr);
651*042d53a7SEvalZero if (rc < 0) {
652*042d53a7SEvalZero ble_phy_disable();
653*042d53a7SEvalZero }
654*042d53a7SEvalZero }
655*042d53a7SEvalZero
656*042d53a7SEvalZero static void
ble_phy_rx_start_isr(void)657*042d53a7SEvalZero ble_phy_rx_start_isr(void)
658*042d53a7SEvalZero {
659*042d53a7SEvalZero int rc;
660*042d53a7SEvalZero uint32_t state;
661*042d53a7SEvalZero uint32_t usecs;
662*042d53a7SEvalZero uint32_t ticks;
663*042d53a7SEvalZero struct ble_mbuf_hdr *ble_hdr;
664*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
665*042d53a7SEvalZero uint8_t *dptr;
666*042d53a7SEvalZero
667*042d53a7SEvalZero dptr = (uint8_t *)&g_ble_phy_rx_buf[0];
668*042d53a7SEvalZero #endif
669*042d53a7SEvalZero
670*042d53a7SEvalZero /* Clear events and clear interrupt */
671*042d53a7SEvalZero NRF_RADIO->EVENTS_ADDRESS = 0;
672*042d53a7SEvalZero
673*042d53a7SEvalZero /* Clear wfr timer channels and DISABLED interrupt */
674*042d53a7SEvalZero NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk | RADIO_INTENCLR_ADDRESS_Msk;
675*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk;
676*042d53a7SEvalZero
677*042d53a7SEvalZero /* Initialize flags, channel and state in ble header at rx start */
678*042d53a7SEvalZero ble_hdr = &g_ble_phy_data.rxhdr;
679*042d53a7SEvalZero ble_hdr->rxinfo.flags = ble_ll_state_get();
680*042d53a7SEvalZero ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan;
681*042d53a7SEvalZero ble_hdr->rxinfo.handle = 0;
682*042d53a7SEvalZero ble_hdr->rxinfo.phy = BLE_PHY_1M;
683*042d53a7SEvalZero ble_hdr->rxinfo.phy_mode = BLE_PHY_MODE_1M;
684*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
685*042d53a7SEvalZero ble_hdr->rxinfo.user_data = NULL;
686*042d53a7SEvalZero #endif
687*042d53a7SEvalZero
688*042d53a7SEvalZero /*
689*042d53a7SEvalZero * Calculate receive start time.
690*042d53a7SEvalZero *
691*042d53a7SEvalZero * XXX: possibly use other routine with remainder!
692*042d53a7SEvalZero */
693*042d53a7SEvalZero usecs = NRF_TIMER0->CC[1] - ble_phy_mode_pdu_start_off(BLE_PHY_MODE_1M);
694*042d53a7SEvalZero ticks = os_cputime_usecs_to_ticks(usecs);
695*042d53a7SEvalZero ble_hdr->rem_usecs = usecs - os_cputime_ticks_to_usecs(ticks);
696*042d53a7SEvalZero if (ble_hdr->rem_usecs == 31) {
697*042d53a7SEvalZero ble_hdr->rem_usecs = 0;
698*042d53a7SEvalZero ++ticks;
699*042d53a7SEvalZero }
700*042d53a7SEvalZero ble_hdr->beg_cputime = g_ble_phy_data.phy_start_cputime + ticks;
701*042d53a7SEvalZero
702*042d53a7SEvalZero /* Wait to get 1st byte of frame */
703*042d53a7SEvalZero while (1) {
704*042d53a7SEvalZero state = NRF_RADIO->STATE;
705*042d53a7SEvalZero if (NRF_RADIO->EVENTS_BCMATCH != 0) {
706*042d53a7SEvalZero break;
707*042d53a7SEvalZero }
708*042d53a7SEvalZero
709*042d53a7SEvalZero /*
710*042d53a7SEvalZero * If state is disabled, we should have the BCMATCH. If not,
711*042d53a7SEvalZero * something is wrong!
712*042d53a7SEvalZero */
713*042d53a7SEvalZero if (state == RADIO_STATE_STATE_Disabled) {
714*042d53a7SEvalZero NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
715*042d53a7SEvalZero NRF_RADIO->SHORTS = 0;
716*042d53a7SEvalZero return;
717*042d53a7SEvalZero }
718*042d53a7SEvalZero }
719*042d53a7SEvalZero
720*042d53a7SEvalZero /* Call Link Layer receive start function */
721*042d53a7SEvalZero rc = ble_ll_rx_start(g_ble_phy_data.rxdptr, g_ble_phy_data.phy_chan,
722*042d53a7SEvalZero &g_ble_phy_data.rxhdr);
723*042d53a7SEvalZero if (rc >= 0) {
724*042d53a7SEvalZero /* Set rx started flag and enable rx end ISR */
725*042d53a7SEvalZero g_ble_phy_data.phy_rx_started = 1;
726*042d53a7SEvalZero NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk;
727*042d53a7SEvalZero
728*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
729*042d53a7SEvalZero /* Must start aar if we need to */
730*042d53a7SEvalZero if (g_ble_phy_data.phy_privacy) {
731*042d53a7SEvalZero NRF_RADIO->EVENTS_BCMATCH = 0;
732*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH23_Msk;
733*042d53a7SEvalZero /*
734*042d53a7SEvalZero * Setup AAR to resolve AdvA and trigger it after complete address
735*042d53a7SEvalZero * is received, i.e. after PDU header and AdvA is received.
736*042d53a7SEvalZero *
737*042d53a7SEvalZero * AdvA starts at 4th octet in receive buffer, after S0, len and S1
738*042d53a7SEvalZero * fields.
739*042d53a7SEvalZero *
740*042d53a7SEvalZero * In case of extended advertising AdvA is located after extended
741*042d53a7SEvalZero * header (+2 octets).
742*042d53a7SEvalZero */
743*042d53a7SEvalZero if (BLE_MBUF_HDR_EXT_ADV(&g_ble_phy_data.rxhdr)) {
744*042d53a7SEvalZero NRF_AAR->ADDRPTR = (uint32_t)(dptr + 5);
745*042d53a7SEvalZero NRF_RADIO->BCC = (BLE_DEV_ADDR_LEN + BLE_LL_PDU_HDR_LEN + 2) * 8;
746*042d53a7SEvalZero
747*042d53a7SEvalZero } else {
748*042d53a7SEvalZero NRF_AAR->ADDRPTR = (uint32_t)(dptr + 3);
749*042d53a7SEvalZero NRF_RADIO->BCC = (BLE_DEV_ADDR_LEN + BLE_LL_PDU_HDR_LEN) * 8;
750*042d53a7SEvalZero }
751*042d53a7SEvalZero }
752*042d53a7SEvalZero #endif
753*042d53a7SEvalZero } else {
754*042d53a7SEvalZero /* Disable PHY */
755*042d53a7SEvalZero ble_phy_disable();
756*042d53a7SEvalZero STATS_INC(ble_phy_stats, rx_aborts);
757*042d53a7SEvalZero }
758*042d53a7SEvalZero
759*042d53a7SEvalZero /* Count rx starts */
760*042d53a7SEvalZero STATS_INC(ble_phy_stats, rx_starts);
761*042d53a7SEvalZero }
762*042d53a7SEvalZero
763*042d53a7SEvalZero static void
ble_phy_isr(void)764*042d53a7SEvalZero ble_phy_isr(void)
765*042d53a7SEvalZero {
766*042d53a7SEvalZero uint32_t irq_en;
767*042d53a7SEvalZero
768*042d53a7SEvalZero os_trace_isr_enter();
769*042d53a7SEvalZero
770*042d53a7SEvalZero /* Read irq register to determine which interrupts are enabled */
771*042d53a7SEvalZero irq_en = NRF_RADIO->INTENCLR;
772*042d53a7SEvalZero
773*042d53a7SEvalZero /*
774*042d53a7SEvalZero * NOTE: order of checking is important! Possible, if things get delayed,
775*042d53a7SEvalZero * we have both an ADDRESS and DISABLED interrupt in rx state. If we get
776*042d53a7SEvalZero * an address, we disable the DISABLED interrupt.
777*042d53a7SEvalZero */
778*042d53a7SEvalZero
779*042d53a7SEvalZero /* We get this if we have started to receive a frame */
780*042d53a7SEvalZero if ((irq_en & RADIO_INTENCLR_ADDRESS_Msk) && NRF_RADIO->EVENTS_ADDRESS) {
781*042d53a7SEvalZero irq_en &= ~RADIO_INTENCLR_DISABLED_Msk;
782*042d53a7SEvalZero ble_phy_rx_start_isr();
783*042d53a7SEvalZero }
784*042d53a7SEvalZero
785*042d53a7SEvalZero /* Check for disabled event. This only happens for transmits now */
786*042d53a7SEvalZero if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) {
787*042d53a7SEvalZero if (g_ble_phy_data.phy_state == BLE_PHY_STATE_RX) {
788*042d53a7SEvalZero NRF_RADIO->EVENTS_DISABLED = 0;
789*042d53a7SEvalZero ble_ll_wfr_timer_exp(NULL);
790*042d53a7SEvalZero } else {
791*042d53a7SEvalZero ble_phy_tx_end_isr();
792*042d53a7SEvalZero }
793*042d53a7SEvalZero }
794*042d53a7SEvalZero
795*042d53a7SEvalZero /* Receive packet end (we dont enable this for transmit) */
796*042d53a7SEvalZero if ((irq_en & RADIO_INTENCLR_END_Msk) && NRF_RADIO->EVENTS_END) {
797*042d53a7SEvalZero ble_phy_rx_end_isr();
798*042d53a7SEvalZero }
799*042d53a7SEvalZero
800*042d53a7SEvalZero /* Ensures IRQ is cleared */
801*042d53a7SEvalZero irq_en = NRF_RADIO->SHORTS;
802*042d53a7SEvalZero
803*042d53a7SEvalZero /* Count # of interrupts */
804*042d53a7SEvalZero STATS_INC(ble_phy_stats, phy_isrs);
805*042d53a7SEvalZero
806*042d53a7SEvalZero os_trace_isr_exit();
807*042d53a7SEvalZero }
808*042d53a7SEvalZero
809*042d53a7SEvalZero /**
810*042d53a7SEvalZero * ble phy init
811*042d53a7SEvalZero *
812*042d53a7SEvalZero * Initialize the PHY.
813*042d53a7SEvalZero *
814*042d53a7SEvalZero * @return int 0: success; PHY error code otherwise
815*042d53a7SEvalZero */
816*042d53a7SEvalZero int
ble_phy_init(void)817*042d53a7SEvalZero ble_phy_init(void)
818*042d53a7SEvalZero {
819*042d53a7SEvalZero int rc;
820*042d53a7SEvalZero
821*042d53a7SEvalZero #if !defined(BLE_XCVR_RFCLK)
822*042d53a7SEvalZero /* BLE wants the HFXO on all the time in this case */
823*042d53a7SEvalZero ble_phy_rfclk_enable();
824*042d53a7SEvalZero
825*042d53a7SEvalZero /*
826*042d53a7SEvalZero * XXX: I do not think we need to wait for settling time here since
827*042d53a7SEvalZero * we will probably not use the radio for longer than the settling time
828*042d53a7SEvalZero * and it will only degrade performance. Might want to wait here though.
829*042d53a7SEvalZero */
830*042d53a7SEvalZero #endif
831*042d53a7SEvalZero
832*042d53a7SEvalZero /* Set phy channel to an invalid channel so first set channel works */
833*042d53a7SEvalZero g_ble_phy_data.phy_chan = BLE_PHY_NUM_CHANS;
834*042d53a7SEvalZero
835*042d53a7SEvalZero /* Toggle peripheral power to reset (just in case) */
836*042d53a7SEvalZero NRF_RADIO->POWER = 0;
837*042d53a7SEvalZero NRF_RADIO->POWER = 1;
838*042d53a7SEvalZero
839*042d53a7SEvalZero /* Disable all interrupts */
840*042d53a7SEvalZero NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
841*042d53a7SEvalZero
842*042d53a7SEvalZero /* Set configuration registers */
843*042d53a7SEvalZero NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit;
844*042d53a7SEvalZero NRF_RADIO->PCNF0 = (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) |
845*042d53a7SEvalZero (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos);
846*042d53a7SEvalZero /* XXX: should maxlen be 251 for encryption? */
847*042d53a7SEvalZero NRF_RADIO->PCNF1 = NRF_MAXLEN |
848*042d53a7SEvalZero (RADIO_PCNF1_ENDIAN_Little << RADIO_PCNF1_ENDIAN_Pos) |
849*042d53a7SEvalZero (NRF_BALEN << RADIO_PCNF1_BALEN_Pos) |
850*042d53a7SEvalZero RADIO_PCNF1_WHITEEN_Msk;
851*042d53a7SEvalZero
852*042d53a7SEvalZero /* Set base0 with the advertising access address */
853*042d53a7SEvalZero NRF_RADIO->BASE0 = (BLE_ACCESS_ADDR_ADV << 8) & 0xFFFFFF00;
854*042d53a7SEvalZero NRF_RADIO->PREFIX0 = (BLE_ACCESS_ADDR_ADV >> 24) & 0xFF;
855*042d53a7SEvalZero
856*042d53a7SEvalZero /* Configure the CRC registers */
857*042d53a7SEvalZero NRF_RADIO->CRCCNF = RADIO_CRCCNF_SKIPADDR_Msk | RADIO_CRCCNF_LEN_Three;
858*042d53a7SEvalZero
859*042d53a7SEvalZero /* Configure BLE poly */
860*042d53a7SEvalZero NRF_RADIO->CRCPOLY = 0x0100065B;
861*042d53a7SEvalZero
862*042d53a7SEvalZero /* Configure IFS */
863*042d53a7SEvalZero NRF_RADIO->TIFS = BLE_LL_IFS;
864*042d53a7SEvalZero
865*042d53a7SEvalZero /* Captures tx/rx start in timer0 cc 1 and tx/rx end in timer0 cc 2 */
866*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH26_Msk | PPI_CHEN_CH27_Msk;
867*042d53a7SEvalZero
868*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
869*042d53a7SEvalZero NRF_CCM->INTENCLR = 0xffffffff;
870*042d53a7SEvalZero NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk;
871*042d53a7SEvalZero NRF_CCM->EVENTS_ERROR = 0;
872*042d53a7SEvalZero memset(g_nrf_encrypt_scratchpad, 0, sizeof(g_nrf_encrypt_scratchpad));
873*042d53a7SEvalZero #endif
874*042d53a7SEvalZero
875*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
876*042d53a7SEvalZero g_ble_phy_data.phy_aar_scratch = 0;
877*042d53a7SEvalZero NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
878*042d53a7SEvalZero NRF_AAR->INTENCLR = 0xffffffff;
879*042d53a7SEvalZero NRF_AAR->EVENTS_END = 0;
880*042d53a7SEvalZero NRF_AAR->EVENTS_RESOLVED = 0;
881*042d53a7SEvalZero NRF_AAR->EVENTS_NOTRESOLVED = 0;
882*042d53a7SEvalZero NRF_AAR->NIRK = 0;
883*042d53a7SEvalZero #endif
884*042d53a7SEvalZero
885*042d53a7SEvalZero /* TIMER0 setup for PHY when using RTC */
886*042d53a7SEvalZero NRF_TIMER0->TASKS_STOP = 1;
887*042d53a7SEvalZero NRF_TIMER0->TASKS_SHUTDOWN = 1;
888*042d53a7SEvalZero NRF_TIMER0->BITMODE = 3; /* 32-bit timer */
889*042d53a7SEvalZero NRF_TIMER0->MODE = 0; /* Timer mode */
890*042d53a7SEvalZero NRF_TIMER0->PRESCALER = 4; /* gives us 1 MHz */
891*042d53a7SEvalZero
892*042d53a7SEvalZero /*
893*042d53a7SEvalZero * PPI setup.
894*042d53a7SEvalZero * Channel 4: Captures TIMER0 in CC[3] when EVENTS_ADDRESS occurs. Used
895*042d53a7SEvalZero * to cancel the wait for response timer.
896*042d53a7SEvalZero * Channel 5: TIMER0 CC[3] to TASKS_DISABLE on radio. This is the wait
897*042d53a7SEvalZero * for response timer.
898*042d53a7SEvalZero */
899*042d53a7SEvalZero NRF_PPI->CH[4].EEP = (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS);
900*042d53a7SEvalZero NRF_PPI->CH[4].TEP = (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[3]);
901*042d53a7SEvalZero NRF_PPI->CH[5].EEP = (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]);
902*042d53a7SEvalZero NRF_PPI->CH[5].TEP = (uint32_t)&(NRF_RADIO->TASKS_DISABLE);
903*042d53a7SEvalZero
904*042d53a7SEvalZero /* Set isr in vector table and enable interrupt */
905*042d53a7SEvalZero NVIC_SetPriority(RADIO_IRQn, 0);
906*042d53a7SEvalZero NVIC_SetVector(RADIO_IRQn, (uint32_t)ble_phy_isr);
907*042d53a7SEvalZero NVIC_EnableIRQ(RADIO_IRQn);
908*042d53a7SEvalZero
909*042d53a7SEvalZero /* Register phy statistics */
910*042d53a7SEvalZero if (!g_ble_phy_data.phy_stats_initialized) {
911*042d53a7SEvalZero rc = stats_init_and_reg(STATS_HDR(ble_phy_stats),
912*042d53a7SEvalZero STATS_SIZE_INIT_PARMS(ble_phy_stats,
913*042d53a7SEvalZero STATS_SIZE_32),
914*042d53a7SEvalZero STATS_NAME_INIT_PARMS(ble_phy_stats),
915*042d53a7SEvalZero "ble_phy");
916*042d53a7SEvalZero assert(rc == 0);
917*042d53a7SEvalZero
918*042d53a7SEvalZero g_ble_phy_data.phy_stats_initialized = 1;
919*042d53a7SEvalZero }
920*042d53a7SEvalZero
921*042d53a7SEvalZero return 0;
922*042d53a7SEvalZero }
923*042d53a7SEvalZero
924*042d53a7SEvalZero /**
925*042d53a7SEvalZero * Puts the phy into receive mode.
926*042d53a7SEvalZero *
927*042d53a7SEvalZero * @return int 0: success; BLE Phy error code otherwise
928*042d53a7SEvalZero */
929*042d53a7SEvalZero int
ble_phy_rx(void)930*042d53a7SEvalZero ble_phy_rx(void)
931*042d53a7SEvalZero {
932*042d53a7SEvalZero /* Check radio state */
933*042d53a7SEvalZero nrf_wait_disabled();
934*042d53a7SEvalZero if (NRF_RADIO->STATE != RADIO_STATE_STATE_Disabled) {
935*042d53a7SEvalZero ble_phy_disable();
936*042d53a7SEvalZero STATS_INC(ble_phy_stats, radio_state_errs);
937*042d53a7SEvalZero return BLE_PHY_ERR_RADIO_STATE;
938*042d53a7SEvalZero }
939*042d53a7SEvalZero
940*042d53a7SEvalZero /* Make sure all interrupts are disabled */
941*042d53a7SEvalZero NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
942*042d53a7SEvalZero
943*042d53a7SEvalZero /* Clear events prior to enabling receive */
944*042d53a7SEvalZero NRF_RADIO->EVENTS_END = 0;
945*042d53a7SEvalZero NRF_RADIO->EVENTS_DISABLED = 0;
946*042d53a7SEvalZero
947*042d53a7SEvalZero /* Setup for rx */
948*042d53a7SEvalZero ble_phy_rx_xcvr_setup();
949*042d53a7SEvalZero
950*042d53a7SEvalZero /* Start the receive task in the radio if not automatically going to rx */
951*042d53a7SEvalZero if ((NRF_PPI->CHEN & PPI_CHEN_CH21_Msk) == 0) {
952*042d53a7SEvalZero NRF_RADIO->TASKS_RXEN = 1;
953*042d53a7SEvalZero }
954*042d53a7SEvalZero
955*042d53a7SEvalZero return 0;
956*042d53a7SEvalZero }
957*042d53a7SEvalZero
958*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
959*042d53a7SEvalZero /**
960*042d53a7SEvalZero * Called to enable encryption at the PHY. Note that this state will persist
961*042d53a7SEvalZero * in the PHY; in other words, if you call this function you have to call
962*042d53a7SEvalZero * disable so that future PHY transmits/receives will not be encrypted.
963*042d53a7SEvalZero *
964*042d53a7SEvalZero * @param pkt_counter
965*042d53a7SEvalZero * @param iv
966*042d53a7SEvalZero * @param key
967*042d53a7SEvalZero * @param is_master
968*042d53a7SEvalZero */
969*042d53a7SEvalZero void
ble_phy_encrypt_enable(uint64_t pkt_counter,uint8_t * iv,uint8_t * key,uint8_t is_master)970*042d53a7SEvalZero ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key,
971*042d53a7SEvalZero uint8_t is_master)
972*042d53a7SEvalZero {
973*042d53a7SEvalZero memcpy(g_nrf_ccm_data.key, key, 16);
974*042d53a7SEvalZero g_nrf_ccm_data.pkt_counter = pkt_counter;
975*042d53a7SEvalZero memcpy(g_nrf_ccm_data.iv, iv, 8);
976*042d53a7SEvalZero g_nrf_ccm_data.dir_bit = is_master;
977*042d53a7SEvalZero g_ble_phy_data.phy_encrypted = 1;
978*042d53a7SEvalZero
979*042d53a7SEvalZero /* Encryption uses LFLEN=5, S1LEN = 3. */
980*042d53a7SEvalZero NRF_RADIO->PCNF0 = (5 << RADIO_PCNF0_LFLEN_Pos) |
981*042d53a7SEvalZero (3 << RADIO_PCNF0_S1LEN_Pos) |
982*042d53a7SEvalZero (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos);
983*042d53a7SEvalZero
984*042d53a7SEvalZero /* Enable the module (AAR cannot be on while CCM on) */
985*042d53a7SEvalZero NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled;
986*042d53a7SEvalZero NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Enabled;
987*042d53a7SEvalZero }
988*042d53a7SEvalZero
989*042d53a7SEvalZero void
ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter,int dir)990*042d53a7SEvalZero ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir)
991*042d53a7SEvalZero {
992*042d53a7SEvalZero g_nrf_ccm_data.pkt_counter = pkt_counter;
993*042d53a7SEvalZero g_nrf_ccm_data.dir_bit = dir;
994*042d53a7SEvalZero }
995*042d53a7SEvalZero
996*042d53a7SEvalZero void
ble_phy_encrypt_disable(void)997*042d53a7SEvalZero ble_phy_encrypt_disable(void)
998*042d53a7SEvalZero {
999*042d53a7SEvalZero NRF_PPI->CHENCLR = (PPI_CHEN_CH24_Msk | PPI_CHEN_CH25_Msk);
1000*042d53a7SEvalZero NRF_CCM->TASKS_STOP = 1;
1001*042d53a7SEvalZero NRF_CCM->EVENTS_ERROR = 0;
1002*042d53a7SEvalZero NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Disabled;
1003*042d53a7SEvalZero
1004*042d53a7SEvalZero /* Switch back to normal length */
1005*042d53a7SEvalZero NRF_RADIO->PCNF0 = (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) |
1006*042d53a7SEvalZero (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos);
1007*042d53a7SEvalZero
1008*042d53a7SEvalZero g_ble_phy_data.phy_encrypted = 0;
1009*042d53a7SEvalZero }
1010*042d53a7SEvalZero #endif
1011*042d53a7SEvalZero
1012*042d53a7SEvalZero void
ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb,void * arg)1013*042d53a7SEvalZero ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg)
1014*042d53a7SEvalZero {
1015*042d53a7SEvalZero /* Set transmit end callback and arg */
1016*042d53a7SEvalZero g_ble_phy_data.txend_cb = txend_cb;
1017*042d53a7SEvalZero g_ble_phy_data.txend_arg = arg;
1018*042d53a7SEvalZero }
1019*042d53a7SEvalZero
1020*042d53a7SEvalZero /**
1021*042d53a7SEvalZero * Called to set the start time of a transmission.
1022*042d53a7SEvalZero *
1023*042d53a7SEvalZero * This function is called to set the start time when we are not going from
1024*042d53a7SEvalZero * rx to tx automatically.
1025*042d53a7SEvalZero *
1026*042d53a7SEvalZero * NOTE: care must be taken when calling this function. The channel should
1027*042d53a7SEvalZero * already be set.
1028*042d53a7SEvalZero *
1029*042d53a7SEvalZero * @param cputime This is the tick at which the 1st bit of the preamble
1030*042d53a7SEvalZero * should be transmitted
1031*042d53a7SEvalZero * @param rem_usecs This is used only when the underlying timing uses a 32.768
1032*042d53a7SEvalZero * kHz crystal. It is the # of usecs from the cputime tick
1033*042d53a7SEvalZero * at which the first bit of the preamble should be
1034*042d53a7SEvalZero * transmitted.
1035*042d53a7SEvalZero * @return int
1036*042d53a7SEvalZero */
1037*042d53a7SEvalZero int
ble_phy_tx_set_start_time(uint32_t cputime,uint8_t rem_usecs)1038*042d53a7SEvalZero ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
1039*042d53a7SEvalZero {
1040*042d53a7SEvalZero int rc;
1041*042d53a7SEvalZero
1042*042d53a7SEvalZero ble_phy_trace_u32x2(BLE_PHY_TRACE_ID_START_TX, cputime, rem_usecs);
1043*042d53a7SEvalZero
1044*042d53a7SEvalZero /* XXX: This should not be necessary, but paranoia is good! */
1045*042d53a7SEvalZero /* Clear timer0 compare to RXEN since we are transmitting */
1046*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
1047*042d53a7SEvalZero
1048*042d53a7SEvalZero /*
1049*042d53a7SEvalZero * XXX: The TXEN time is 140 usecs but there may be additional delays
1050*042d53a7SEvalZero * Need to look at this.
1051*042d53a7SEvalZero */
1052*042d53a7SEvalZero if (ble_phy_set_start_time(cputime, rem_usecs) != 0) {
1053*042d53a7SEvalZero STATS_INC(ble_phy_stats, tx_late);
1054*042d53a7SEvalZero ble_phy_disable();
1055*042d53a7SEvalZero rc = BLE_PHY_ERR_TX_LATE;
1056*042d53a7SEvalZero } else {
1057*042d53a7SEvalZero /* Enable PPI to automatically start TXEN */
1058*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk;
1059*042d53a7SEvalZero rc = 0;
1060*042d53a7SEvalZero }
1061*042d53a7SEvalZero return rc;
1062*042d53a7SEvalZero }
1063*042d53a7SEvalZero /**
1064*042d53a7SEvalZero * Called to set the start time of a reception
1065*042d53a7SEvalZero *
1066*042d53a7SEvalZero * This function acts a bit differently than transmit. If we are late getting
1067*042d53a7SEvalZero * here we will still attempt to receive.
1068*042d53a7SEvalZero *
1069*042d53a7SEvalZero * NOTE: care must be taken when calling this function. The channel should
1070*042d53a7SEvalZero * already be set.
1071*042d53a7SEvalZero *
1072*042d53a7SEvalZero * @param cputime
1073*042d53a7SEvalZero *
1074*042d53a7SEvalZero * @return int
1075*042d53a7SEvalZero */
1076*042d53a7SEvalZero int
ble_phy_rx_set_start_time(uint32_t cputime,uint8_t rem_usecs)1077*042d53a7SEvalZero ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
1078*042d53a7SEvalZero {
1079*042d53a7SEvalZero int rc;
1080*042d53a7SEvalZero
1081*042d53a7SEvalZero ble_phy_trace_u32x2(BLE_PHY_TRACE_ID_START_RX, cputime, rem_usecs);
1082*042d53a7SEvalZero
1083*042d53a7SEvalZero /* XXX: This should not be necessary, but paranoia is good! */
1084*042d53a7SEvalZero /* Clear timer0 compare to TXEN since we are transmitting */
1085*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk;
1086*042d53a7SEvalZero
1087*042d53a7SEvalZero /*
1088*042d53a7SEvalZero * XXX: The RXEN time is 138 usecs but there may be additional delays
1089*042d53a7SEvalZero * Need to look at this.
1090*042d53a7SEvalZero */
1091*042d53a7SEvalZero if (ble_phy_set_start_time(cputime, rem_usecs) != 0) {
1092*042d53a7SEvalZero STATS_INC(ble_phy_stats, rx_late);
1093*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
1094*042d53a7SEvalZero NRF_RADIO->TASKS_RXEN = 1;
1095*042d53a7SEvalZero rc = BLE_PHY_ERR_RX_LATE;
1096*042d53a7SEvalZero } else {
1097*042d53a7SEvalZero /* Enable PPI to automatically start RXEN */
1098*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk;
1099*042d53a7SEvalZero
1100*042d53a7SEvalZero /* Start rx */
1101*042d53a7SEvalZero rc = ble_phy_rx();
1102*042d53a7SEvalZero }
1103*042d53a7SEvalZero return rc;
1104*042d53a7SEvalZero }
1105*042d53a7SEvalZero
1106*042d53a7SEvalZero int
ble_phy_tx(ble_phy_tx_pducb_t pducb,void * pducb_arg,uint8_t end_trans)1107*042d53a7SEvalZero ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans)
1108*042d53a7SEvalZero {
1109*042d53a7SEvalZero int rc;
1110*042d53a7SEvalZero uint8_t *dptr;
1111*042d53a7SEvalZero uint8_t payload_len;
1112*042d53a7SEvalZero uint8_t payload_off;
1113*042d53a7SEvalZero uint8_t hdr_byte;
1114*042d53a7SEvalZero uint32_t state;
1115*042d53a7SEvalZero uint32_t shortcuts;
1116*042d53a7SEvalZero
1117*042d53a7SEvalZero /*
1118*042d53a7SEvalZero * This check is to make sure that the radio is not in a state where
1119*042d53a7SEvalZero * it is moving to disabled state. If so, let it get there.
1120*042d53a7SEvalZero */
1121*042d53a7SEvalZero nrf_wait_disabled();
1122*042d53a7SEvalZero
1123*042d53a7SEvalZero /*
1124*042d53a7SEvalZero * XXX: Although we may not have to do this here, I clear all the PPI
1125*042d53a7SEvalZero * that should not be used when transmitting. Some of them are only enabled
1126*042d53a7SEvalZero * if encryption and/or privacy is on, but I dont care. Better to be
1127*042d53a7SEvalZero * paranoid, and if you are going to clear one, might as well clear them
1128*042d53a7SEvalZero * all.
1129*042d53a7SEvalZero */
1130*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | PPI_CHEN_CH23_Msk |
1131*042d53a7SEvalZero PPI_CHEN_CH25_Msk;
1132*042d53a7SEvalZero
1133*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
1134*042d53a7SEvalZero if (g_ble_phy_data.phy_encrypted) {
1135*042d53a7SEvalZero /* RAM representation has S0, LENGTH and S1 fields. (3 bytes) */
1136*042d53a7SEvalZero dptr = (uint8_t *)&g_ble_phy_enc_buf[0];
1137*042d53a7SEvalZero payload_off = 3;
1138*042d53a7SEvalZero
1139*042d53a7SEvalZero NRF_CCM->SHORTS = 1;
1140*042d53a7SEvalZero NRF_CCM->INPTR = (uint32_t)&g_ble_phy_enc_buf[0];
1141*042d53a7SEvalZero NRF_CCM->OUTPTR = (uint32_t)&g_ble_phy_tx_buf[0];
1142*042d53a7SEvalZero NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0];
1143*042d53a7SEvalZero NRF_CCM->EVENTS_ERROR = 0;
1144*042d53a7SEvalZero NRF_CCM->MODE = CCM_MODE_MODE_Encryption;
1145*042d53a7SEvalZero NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data;
1146*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH24_Msk;
1147*042d53a7SEvalZero } else {
1148*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
1149*042d53a7SEvalZero /* Reconfigure PCNF0 */
1150*042d53a7SEvalZero NRF_RADIO->PCNF0 = (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) |
1151*042d53a7SEvalZero (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos);
1152*042d53a7SEvalZero NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
1153*042d53a7SEvalZero #endif
1154*042d53a7SEvalZero /* RAM representation has S0 and LENGTH fields (2 bytes) */
1155*042d53a7SEvalZero dptr = (uint8_t *)&g_ble_phy_tx_buf[0];
1156*042d53a7SEvalZero payload_off = 2;
1157*042d53a7SEvalZero }
1158*042d53a7SEvalZero #else
1159*042d53a7SEvalZero
1160*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
1161*042d53a7SEvalZero /* Reconfigure PCNF0 */
1162*042d53a7SEvalZero NRF_RADIO->PCNF0 = (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) |
1163*042d53a7SEvalZero (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos);
1164*042d53a7SEvalZero #endif
1165*042d53a7SEvalZero
1166*042d53a7SEvalZero /* RAM representation has S0 and LENGTH fields (2 bytes) */
1167*042d53a7SEvalZero dptr = (uint8_t *)&g_ble_phy_tx_buf[0];
1168*042d53a7SEvalZero payload_off = 2;
1169*042d53a7SEvalZero #endif
1170*042d53a7SEvalZero
1171*042d53a7SEvalZero NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_tx_buf[0];
1172*042d53a7SEvalZero
1173*042d53a7SEvalZero /* Clear the ready, end and disabled events */
1174*042d53a7SEvalZero NRF_RADIO->EVENTS_READY = 0;
1175*042d53a7SEvalZero NRF_RADIO->EVENTS_END = 0;
1176*042d53a7SEvalZero NRF_RADIO->EVENTS_DISABLED = 0;
1177*042d53a7SEvalZero
1178*042d53a7SEvalZero /* Enable shortcuts for transmit start/end. */
1179*042d53a7SEvalZero shortcuts = RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk;
1180*042d53a7SEvalZero if (end_trans == BLE_PHY_TRANSITION_TX_RX) {
1181*042d53a7SEvalZero shortcuts |= RADIO_SHORTS_DISABLED_RXEN_Msk;
1182*042d53a7SEvalZero }
1183*042d53a7SEvalZero NRF_RADIO->SHORTS = shortcuts;
1184*042d53a7SEvalZero NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk;
1185*042d53a7SEvalZero
1186*042d53a7SEvalZero /* Set PDU payload */
1187*042d53a7SEvalZero payload_len = pducb(&dptr[payload_off], pducb_arg, &hdr_byte);
1188*042d53a7SEvalZero
1189*042d53a7SEvalZero /* Set PDU header */
1190*042d53a7SEvalZero dptr[0] = hdr_byte;
1191*042d53a7SEvalZero dptr[1] = payload_len;
1192*042d53a7SEvalZero if (payload_off > 2) {
1193*042d53a7SEvalZero dptr[2] = 0;
1194*042d53a7SEvalZero }
1195*042d53a7SEvalZero
1196*042d53a7SEvalZero /* Set the PHY transition */
1197*042d53a7SEvalZero g_ble_phy_data.phy_transition = end_trans;
1198*042d53a7SEvalZero
1199*042d53a7SEvalZero /* Set transmitted payload length */
1200*042d53a7SEvalZero g_ble_phy_data.phy_tx_pyld_len = payload_len;
1201*042d53a7SEvalZero
1202*042d53a7SEvalZero /* If we already started transmitting, abort it! */
1203*042d53a7SEvalZero state = NRF_RADIO->STATE;
1204*042d53a7SEvalZero if (state != RADIO_STATE_STATE_Tx) {
1205*042d53a7SEvalZero
1206*042d53a7SEvalZero /* Set phy state to transmitting and count packet statistics */
1207*042d53a7SEvalZero g_ble_phy_data.phy_state = BLE_PHY_STATE_TX;
1208*042d53a7SEvalZero STATS_INC(ble_phy_stats, tx_good);
1209*042d53a7SEvalZero STATS_INCN(ble_phy_stats, tx_bytes, payload_len + BLE_LL_PDU_HDR_LEN);
1210*042d53a7SEvalZero rc = BLE_ERR_SUCCESS;
1211*042d53a7SEvalZero } else {
1212*042d53a7SEvalZero ble_phy_disable();
1213*042d53a7SEvalZero STATS_INC(ble_phy_stats, tx_late);
1214*042d53a7SEvalZero rc = BLE_PHY_ERR_RADIO_STATE;
1215*042d53a7SEvalZero }
1216*042d53a7SEvalZero
1217*042d53a7SEvalZero return rc;
1218*042d53a7SEvalZero }
1219*042d53a7SEvalZero
1220*042d53a7SEvalZero /**
1221*042d53a7SEvalZero * ble phy txpwr set
1222*042d53a7SEvalZero *
1223*042d53a7SEvalZero * Set the transmit output power (in dBm).
1224*042d53a7SEvalZero *
1225*042d53a7SEvalZero * NOTE: If the output power specified is within the BLE limits but outside
1226*042d53a7SEvalZero * the chip limits, we "rail" the power level so we dont exceed the min/max
1227*042d53a7SEvalZero * chip values.
1228*042d53a7SEvalZero *
1229*042d53a7SEvalZero * @param dbm Power output in dBm.
1230*042d53a7SEvalZero *
1231*042d53a7SEvalZero * @return int 0: success; anything else is an error
1232*042d53a7SEvalZero */
1233*042d53a7SEvalZero int
ble_phy_txpwr_set(int dbm)1234*042d53a7SEvalZero ble_phy_txpwr_set(int dbm)
1235*042d53a7SEvalZero {
1236*042d53a7SEvalZero /* Check valid range */
1237*042d53a7SEvalZero assert(dbm <= BLE_PHY_MAX_PWR_DBM);
1238*042d53a7SEvalZero
1239*042d53a7SEvalZero /* "Rail" power level if outside supported range */
1240*042d53a7SEvalZero if (dbm > NRF_TX_PWR_MAX_DBM) {
1241*042d53a7SEvalZero dbm = NRF_TX_PWR_MAX_DBM;
1242*042d53a7SEvalZero } else {
1243*042d53a7SEvalZero if (dbm < NRF_TX_PWR_MIN_DBM) {
1244*042d53a7SEvalZero dbm = NRF_TX_PWR_MIN_DBM;
1245*042d53a7SEvalZero }
1246*042d53a7SEvalZero }
1247*042d53a7SEvalZero
1248*042d53a7SEvalZero NRF_RADIO->TXPOWER = dbm;
1249*042d53a7SEvalZero g_ble_phy_data.phy_txpwr_dbm = dbm;
1250*042d53a7SEvalZero
1251*042d53a7SEvalZero return 0;
1252*042d53a7SEvalZero }
1253*042d53a7SEvalZero
1254*042d53a7SEvalZero /**
1255*042d53a7SEvalZero * ble phy txpwr round
1256*042d53a7SEvalZero *
1257*042d53a7SEvalZero * Get the rounded transmit output power (in dBm).
1258*042d53a7SEvalZero *
1259*042d53a7SEvalZero * @param dbm Power output in dBm.
1260*042d53a7SEvalZero *
1261*042d53a7SEvalZero * @return int Rounded power in dBm
1262*042d53a7SEvalZero */
ble_phy_txpower_round(int dbm)1263*042d53a7SEvalZero int ble_phy_txpower_round(int dbm)
1264*042d53a7SEvalZero {
1265*042d53a7SEvalZero /* "Rail" power level if outside supported range */
1266*042d53a7SEvalZero if (dbm > NRF_TX_PWR_MAX_DBM) {
1267*042d53a7SEvalZero dbm = NRF_TX_PWR_MAX_DBM;
1268*042d53a7SEvalZero } else {
1269*042d53a7SEvalZero if (dbm < NRF_TX_PWR_MIN_DBM) {
1270*042d53a7SEvalZero dbm = NRF_TX_PWR_MIN_DBM;
1271*042d53a7SEvalZero }
1272*042d53a7SEvalZero }
1273*042d53a7SEvalZero
1274*042d53a7SEvalZero return dbm;
1275*042d53a7SEvalZero }
1276*042d53a7SEvalZero
1277*042d53a7SEvalZero /**
1278*042d53a7SEvalZero * ble phy txpwr get
1279*042d53a7SEvalZero *
1280*042d53a7SEvalZero * Get the transmit power.
1281*042d53a7SEvalZero *
1282*042d53a7SEvalZero * @return int The current PHY transmit power, in dBm
1283*042d53a7SEvalZero */
1284*042d53a7SEvalZero int
ble_phy_txpwr_get(void)1285*042d53a7SEvalZero ble_phy_txpwr_get(void)
1286*042d53a7SEvalZero {
1287*042d53a7SEvalZero return g_ble_phy_data.phy_txpwr_dbm;
1288*042d53a7SEvalZero }
1289*042d53a7SEvalZero
1290*042d53a7SEvalZero /**
1291*042d53a7SEvalZero * ble phy setchan
1292*042d53a7SEvalZero *
1293*042d53a7SEvalZero * Sets the logical frequency of the transceiver. The input parameter is the
1294*042d53a7SEvalZero * BLE channel index (0 to 39, inclusive). The NRF frequency register works like
1295*042d53a7SEvalZero * this: logical frequency = 2400 + FREQ (MHz).
1296*042d53a7SEvalZero *
1297*042d53a7SEvalZero * Thus, to get a logical frequency of 2402 MHz, you would program the
1298*042d53a7SEvalZero * FREQUENCY register to 2.
1299*042d53a7SEvalZero *
1300*042d53a7SEvalZero * @param chan This is the Data Channel Index or Advertising Channel index
1301*042d53a7SEvalZero *
1302*042d53a7SEvalZero * @return int 0: success; PHY error code otherwise
1303*042d53a7SEvalZero */
1304*042d53a7SEvalZero int
ble_phy_setchan(uint8_t chan,uint32_t access_addr,uint32_t crcinit)1305*042d53a7SEvalZero ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit)
1306*042d53a7SEvalZero {
1307*042d53a7SEvalZero uint32_t prefix;
1308*042d53a7SEvalZero
1309*042d53a7SEvalZero assert(chan < BLE_PHY_NUM_CHANS);
1310*042d53a7SEvalZero
1311*042d53a7SEvalZero /* Check for valid channel range */
1312*042d53a7SEvalZero if (chan >= BLE_PHY_NUM_CHANS) {
1313*042d53a7SEvalZero return BLE_PHY_ERR_INV_PARAM;
1314*042d53a7SEvalZero }
1315*042d53a7SEvalZero
1316*042d53a7SEvalZero /* Get correct frequency */
1317*042d53a7SEvalZero if (chan < BLE_PHY_NUM_DATA_CHANS) {
1318*042d53a7SEvalZero /* Set current access address */
1319*042d53a7SEvalZero g_ble_phy_data.phy_access_address = access_addr;
1320*042d53a7SEvalZero
1321*042d53a7SEvalZero /* Configure logical address 1 and crcinit */
1322*042d53a7SEvalZero prefix = NRF_RADIO->PREFIX0;
1323*042d53a7SEvalZero prefix &= 0xffff00ff;
1324*042d53a7SEvalZero prefix |= ((access_addr >> 24) & 0xFF) << 8;
1325*042d53a7SEvalZero NRF_RADIO->BASE1 = (access_addr << 8) & 0xFFFFFF00;
1326*042d53a7SEvalZero NRF_RADIO->PREFIX0 = prefix;
1327*042d53a7SEvalZero NRF_RADIO->TXADDRESS = 1;
1328*042d53a7SEvalZero NRF_RADIO->RXADDRESSES = (1 << 1);
1329*042d53a7SEvalZero NRF_RADIO->CRCINIT = crcinit;
1330*042d53a7SEvalZero } else {
1331*042d53a7SEvalZero /* Logical adddress 0 preconfigured */
1332*042d53a7SEvalZero NRF_RADIO->TXADDRESS = 0;
1333*042d53a7SEvalZero NRF_RADIO->RXADDRESSES = (1 << 0);
1334*042d53a7SEvalZero NRF_RADIO->CRCINIT = BLE_LL_CRCINIT_ADV;
1335*042d53a7SEvalZero
1336*042d53a7SEvalZero /* Set current access address */
1337*042d53a7SEvalZero g_ble_phy_data.phy_access_address = BLE_ACCESS_ADDR_ADV;
1338*042d53a7SEvalZero }
1339*042d53a7SEvalZero
1340*042d53a7SEvalZero /* Set the frequency and the data whitening initial value */
1341*042d53a7SEvalZero g_ble_phy_data.phy_chan = chan;
1342*042d53a7SEvalZero NRF_RADIO->FREQUENCY = g_ble_phy_chan_freq[chan];
1343*042d53a7SEvalZero NRF_RADIO->DATAWHITEIV = chan;
1344*042d53a7SEvalZero
1345*042d53a7SEvalZero return 0;
1346*042d53a7SEvalZero }
1347*042d53a7SEvalZero
1348*042d53a7SEvalZero /**
1349*042d53a7SEvalZero * Stop the timer used to count microseconds when using RTC for cputime
1350*042d53a7SEvalZero */
1351*042d53a7SEvalZero void
ble_phy_stop_usec_timer(void)1352*042d53a7SEvalZero ble_phy_stop_usec_timer(void)
1353*042d53a7SEvalZero {
1354*042d53a7SEvalZero NRF_TIMER0->TASKS_STOP = 1;
1355*042d53a7SEvalZero NRF_TIMER0->TASKS_SHUTDOWN = 1;
1356*042d53a7SEvalZero NRF_RTC0->EVTENCLR = RTC_EVTENSET_COMPARE0_Msk;
1357*042d53a7SEvalZero }
1358*042d53a7SEvalZero
1359*042d53a7SEvalZero /**
1360*042d53a7SEvalZero * ble phy disable irq and ppi
1361*042d53a7SEvalZero *
1362*042d53a7SEvalZero * This routine is to be called when reception was stopped due to either a
1363*042d53a7SEvalZero * wait for response timeout or a packet being received and the phy is to be
1364*042d53a7SEvalZero * restarted in receive mode. Generally, the disable routine is called to stop
1365*042d53a7SEvalZero * the phy.
1366*042d53a7SEvalZero */
1367*042d53a7SEvalZero void
ble_phy_disable_irq_and_ppi(void)1368*042d53a7SEvalZero ble_phy_disable_irq_and_ppi(void)
1369*042d53a7SEvalZero {
1370*042d53a7SEvalZero NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
1371*042d53a7SEvalZero NRF_RADIO->SHORTS = 0;
1372*042d53a7SEvalZero NRF_RADIO->TASKS_DISABLE = 1;
1373*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | PPI_CHEN_CH20_Msk |
1374*042d53a7SEvalZero PPI_CHEN_CH21_Msk | PPI_CHEN_CH23_Msk | PPI_CHEN_CH24_Msk |
1375*042d53a7SEvalZero PPI_CHEN_CH25_Msk | PPI_CHEN_CH31_Msk;
1376*042d53a7SEvalZero NVIC_ClearPendingIRQ(RADIO_IRQn);
1377*042d53a7SEvalZero g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE;
1378*042d53a7SEvalZero }
1379*042d53a7SEvalZero
1380*042d53a7SEvalZero void
ble_phy_restart_rx(void)1381*042d53a7SEvalZero ble_phy_restart_rx(void)
1382*042d53a7SEvalZero {
1383*042d53a7SEvalZero ble_phy_disable_irq_and_ppi();
1384*042d53a7SEvalZero ble_phy_rx();
1385*042d53a7SEvalZero }
1386*042d53a7SEvalZero
1387*042d53a7SEvalZero /**
1388*042d53a7SEvalZero * ble phy disable
1389*042d53a7SEvalZero *
1390*042d53a7SEvalZero * Disables the PHY. This should be called when an event is over. It stops
1391*042d53a7SEvalZero * the usec timer (if used), disables interrupts, disables the RADIO, disables
1392*042d53a7SEvalZero * PPI and sets state to idle.
1393*042d53a7SEvalZero */
1394*042d53a7SEvalZero void
ble_phy_disable(void)1395*042d53a7SEvalZero ble_phy_disable(void)
1396*042d53a7SEvalZero {
1397*042d53a7SEvalZero ble_phy_trace_void(BLE_PHY_TRACE_ID_DISABLE);
1398*042d53a7SEvalZero
1399*042d53a7SEvalZero ble_phy_stop_usec_timer();
1400*042d53a7SEvalZero ble_phy_disable_irq_and_ppi();
1401*042d53a7SEvalZero }
1402*042d53a7SEvalZero
1403*042d53a7SEvalZero /* Gets the current access address */
ble_phy_access_addr_get(void)1404*042d53a7SEvalZero uint32_t ble_phy_access_addr_get(void)
1405*042d53a7SEvalZero {
1406*042d53a7SEvalZero return g_ble_phy_data.phy_access_address;
1407*042d53a7SEvalZero }
1408*042d53a7SEvalZero
1409*042d53a7SEvalZero /**
1410*042d53a7SEvalZero * Return the phy state
1411*042d53a7SEvalZero *
1412*042d53a7SEvalZero * @return int The current PHY state.
1413*042d53a7SEvalZero */
1414*042d53a7SEvalZero int
ble_phy_state_get(void)1415*042d53a7SEvalZero ble_phy_state_get(void)
1416*042d53a7SEvalZero {
1417*042d53a7SEvalZero return g_ble_phy_data.phy_state;
1418*042d53a7SEvalZero }
1419*042d53a7SEvalZero
1420*042d53a7SEvalZero /**
1421*042d53a7SEvalZero * Called to see if a reception has started
1422*042d53a7SEvalZero *
1423*042d53a7SEvalZero * @return int
1424*042d53a7SEvalZero */
1425*042d53a7SEvalZero int
ble_phy_rx_started(void)1426*042d53a7SEvalZero ble_phy_rx_started(void)
1427*042d53a7SEvalZero {
1428*042d53a7SEvalZero return g_ble_phy_data.phy_rx_started;
1429*042d53a7SEvalZero }
1430*042d53a7SEvalZero
1431*042d53a7SEvalZero /**
1432*042d53a7SEvalZero * Return the transceiver state
1433*042d53a7SEvalZero *
1434*042d53a7SEvalZero * @return int transceiver state.
1435*042d53a7SEvalZero */
1436*042d53a7SEvalZero uint8_t
ble_phy_xcvr_state_get(void)1437*042d53a7SEvalZero ble_phy_xcvr_state_get(void)
1438*042d53a7SEvalZero {
1439*042d53a7SEvalZero uint32_t state;
1440*042d53a7SEvalZero state = NRF_RADIO->STATE;
1441*042d53a7SEvalZero return (uint8_t)state;
1442*042d53a7SEvalZero }
1443*042d53a7SEvalZero
1444*042d53a7SEvalZero /**
1445*042d53a7SEvalZero * Called to return the maximum data pdu payload length supported by the
1446*042d53a7SEvalZero * phy. For this chip, if encryption is enabled, the maximum payload is 27
1447*042d53a7SEvalZero * bytes.
1448*042d53a7SEvalZero *
1449*042d53a7SEvalZero * @return uint8_t Maximum data channel PDU payload size supported
1450*042d53a7SEvalZero */
1451*042d53a7SEvalZero uint8_t
ble_phy_max_data_pdu_pyld(void)1452*042d53a7SEvalZero ble_phy_max_data_pdu_pyld(void)
1453*042d53a7SEvalZero {
1454*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
1455*042d53a7SEvalZero return NRF_MAX_ENCRYPTED_PYLD_LEN;
1456*042d53a7SEvalZero #else
1457*042d53a7SEvalZero return BLE_LL_DATA_PDU_MAX_PYLD;
1458*042d53a7SEvalZero #endif
1459*042d53a7SEvalZero }
1460*042d53a7SEvalZero
1461*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
1462*042d53a7SEvalZero void
ble_phy_resolv_list_enable(void)1463*042d53a7SEvalZero ble_phy_resolv_list_enable(void)
1464*042d53a7SEvalZero {
1465*042d53a7SEvalZero NRF_AAR->NIRK = (uint32_t)g_nrf_num_irks;
1466*042d53a7SEvalZero g_ble_phy_data.phy_privacy = 1;
1467*042d53a7SEvalZero }
1468*042d53a7SEvalZero
1469*042d53a7SEvalZero void
ble_phy_resolv_list_disable(void)1470*042d53a7SEvalZero ble_phy_resolv_list_disable(void)
1471*042d53a7SEvalZero {
1472*042d53a7SEvalZero g_ble_phy_data.phy_privacy = 0;
1473*042d53a7SEvalZero }
1474*042d53a7SEvalZero #endif
1475*042d53a7SEvalZero
1476*042d53a7SEvalZero void
ble_phy_rfclk_enable(void)1477*042d53a7SEvalZero ble_phy_rfclk_enable(void)
1478*042d53a7SEvalZero {
1479*042d53a7SEvalZero #if MYNEWT
1480*042d53a7SEvalZero nrf51_clock_hfxo_request();
1481*042d53a7SEvalZero #else
1482*042d53a7SEvalZero NRF_CLOCK->TASKS_HFCLKSTART = 1;
1483*042d53a7SEvalZero #endif
1484*042d53a7SEvalZero }
1485*042d53a7SEvalZero
1486*042d53a7SEvalZero void
ble_phy_rfclk_disable(void)1487*042d53a7SEvalZero ble_phy_rfclk_disable(void)
1488*042d53a7SEvalZero {
1489*042d53a7SEvalZero #if MYNEWT
1490*042d53a7SEvalZero nrf51_clock_hfxo_release();
1491*042d53a7SEvalZero #else
1492*042d53a7SEvalZero NRF_CLOCK->TASKS_HFCLKSTOP = 1;
1493*042d53a7SEvalZero #endif
1494*042d53a7SEvalZero }
1495