1 /*
2  * Copyright (c) 2017 Oticon A/S
3  * Copyright (c) 2023 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 #include <string.h>
8 #include <stdbool.h>
9 #include <stdint.h>
10 #include "bs_types.h"
11 #include "bs_tracing.h"
12 #include "bs_utils.h"
13 #include "bs_pc_2G4.h"
14 #include "bs_pc_2G4_utils.h"
15 #include "time_machine_if.h"
16 #include "NRF_RADIO.h"
17 #include "NRF_HW_model_top.h"
18 #include "NRF_PPI.h"
19 #include "NRF_AES_CCM.h"
20 #include "irq_ctrl.h"
21 #include "NRF_HWLowL.h"
22 #include "crc.h"
23 #include "NRF_RADIO_signals.h"
24 #include "NRF_RADIO_utils.h"
25 #include "NRF_RADIO_timings.h"
26 #include "NRF_RADIO_bitcounter.h"
27 #include "NRF_RADIO_priv.h"
28 
29 /**
30  * RADIO — 2.4 GHz Radio
31  * https://infocenter.nordicsemi.com/topic/ps_nrf52833/radio.html?cp=4_1_0_5_17
32  *
33  * Note: as of now, only 1&2Mbps BLE & 15.4 packet formats are supported, there is quite many notes around in the code
34  * where changes would be required to support other formats
35  *
36  * Note3: Only logical address 0 (in Tx or Rx) is supported
37  *
38  * Note4: only default freq. map supported
39  *
40  * Note5: Only little endian hosts supported (x86 is little endian)
41  *
42  * Note6: RSSI is always sampled at the end of the address (and RSSIEND raised there)
43  *
44  * Note7: Whitening is always/never "used" (it is the phy who would use or not whitening), the radio model can assume it is always used (even that we ignore the initialization register)
45  *
46  * Note8: During idle nothing is sent to the air
47  *
48  * Note9: Double buffering of registers is not implemented. Changing the register during the packet Tx/Rx will cause trouble
49  *        It should be (at least): PACKETPTR @ START
50  *                                 MODE @ TXEN | RXEN
51  *                                 CRC config @ START
52  *
53  * Note10: Maxlength is only partially checked (the packet is cut, but the interaction with the phy is not proper)
54  *
55  * Note11: Only the BLE & 15.4 CRC polynomials are supported
56  *         During reception we assume that CRCPOLY and CRCINIT are correct on both sides, and just rely on the phy bit error reporting to save processing time
57  *         On transmission we generate the correct CRC for correctness of the channel dump traces (and Ellisys traces)
58  * Note11b:The CRC configuration is directly deduced from the modulation, only BLE and 154 CRCs are supported so far
59  *
60  * Note12: * CCA or ED procedures cannot be performed while the RADIO is performing an actual packet reception (they are exclusive)
61  *         * In CCA Mode2 & 3, this model (due to the Phy) does not search for a SFD, or for a correlation peak
62  *           instead it searches for a compatible modulation of sufficient power (which is in line with what the 802.15.4
63  *           standard specifies)
64  *
65  * Note13: Nothing related to AoA/AoD features (CTE, DFE) is implemented
66  *
67  * Note14: Several 52833 radio state change events are not yet implemented
68  *         (EVENTS_RATEBOOST, EVENTS_MHRMATCH & EVENTS_CTEPRESENT)
69  *
70  * Note15: PDUSTAT not yet implemented
71  *
72  * Note16: No antenna switching
73  *
74  * Note17: Interrupts are modeled as pulses to the NVIC, not level interrupts as they are in reality
75  *
76  * Note18: EVENTS_SYNC:
77  *         a) It is not generated at the exact correct time:
78  *         In this model it is generated at the end of the address (or SFD)
79  *         while according to the infocenter spec this should come at the end of the preamble,
80  *         and only if in coded and 15.4 mode.
81  *         In reality it seems to come somewhere during the preamble for 15.4 and coded phy,
82  *         and somewhere during the address for 1&2Mbps BLE.
83  *         In any case this seems to be a debug signal, and a quite imprecise one,
84  *         so the assumption is that nobody uses it for anything timing critical.
85  *         b) it is only generated when there is a full address match. While in real HW this is not required
86  *         (so false positives happen in real HW)
87  *
88  * Note19: EVENTS_PHYEND
89  *         It is not generated at the exact correct time. In the model it is generated at the
90  *         exact same time as END. While according to the spec, it should be generated with the last
91  *         bit on *air* (That is the Tx chain delay later for Tx, and RxChainDelay earlier for Rx)
92  *
93  * Note20: The LQI value is based on a single measurement at the end of the SFD.
94  *         While the real HW samples it in 3 places during the payload, and the middle one selected.
95  *
96  * Note21: Timings:
97  *          * Radio ramp down time for 2Mbps BLE is 2 microseconds too long.
98  *          * Many timings are simplified, and some events which take slightly different amounts of time to occur
99  *            are produced at the same time as others, or so. Check NRF_RADIO_timings.c for some more notes.
100  *
101  * Note22: EVENTS_FRAMESTART
102  *          * It is generated for all modulation types, this seems to be how the HW behaves even if the spec
103  *            seems to mildly imply it is only for 15.4
104  *          * In Tx: The spec seems unclear about the FRAMESTART being generated or not (after SHR).
105  *            Drawings imply it is, the text that it does not. The HW does. The model does generate it after SHR.
106  *          * In Rx: In the model it is generated at the SHR/SFD end (not PHR), meaning, at the same time as the ADDRESS EVENT
107  *            The spec seems to contradict itself here. But seems in real HW it is generated at the end of the PHR.
108  *
109  * Note23: Powering off/on is not properly modeled (it is mostly ignored)
110  *
111  *
112  * Implementation Specification:
113  *   A diagram of the main state machine can be found in docs/RADIO_states.svg
114  *   That main state machine is driven by a timer (Timer_RADIO) which results in calls to nrf_radio_timer_triggered()
115  *   and the tasks which cause transitions and/or the timer to be set to a new value.
116  *
117  *   Apart from this main state machine there is a small state machine for handling the automatic TIFS re-enabling.
118  *   See TIFS_state, Timer_TIFS, nrf_radio_fake_task_TRXEN_TIFS, and maybe_prepare_TIFS()
119  *   This TIFS machine piggybacks on the main machine and its timer.
120  *
121  *   And apart from this, there is an "abort" state machine, which is used to handle SW or another peripheral
122  *   triggering a TASK which requires us to stop a transaction with the Phy midway.
123  *   The idea here, is that when we start a transaction with the Phy (say a Tx), we do not know at the start if something
124  *   will want to stop it midway. So we tell the Phy when we start, when we expect to end, but also, when we
125  *   want the Phy to recheck with us if the transaction needs to be aborted midway.
126  *   This recheck time is set to the time anything may decide to stop. Which for simplicity is whenever *anything* may run.
127  *   That is, whenever any timer is scheduled. As this includes other peripherals which may trigger tasks thru the PPI,
128  *   or SW doing so after an interrupt.
129  *   If at any point, a TASK that stops a transaction comes while that transaction is ongoing, the abort state machine will flag it,
130  *   and the next time we need to respond to the Phy we will tell that we are stopping.
131  *
132  *   Apart from these, there is the interaction with the Phy (check ext_2G4_libPhyComv1/docs):
133  *   There is 3 different procedures for this (Tx, Rx & CCA) which fundamentally work in the same way.
134  *   At start_Rx/Tx/CCA_ED() (which is called at the micros when the actual Tx/Rx/CCA/ED measurement starts),
135  *   the Phy is told we want to start, and immediately we block until we get a response from the Phy.
136  *   (1) Here the response may be that:
137  *     * The Phy finished the procedure, in which case we just pre-program the main state machine timer,
138  *       and set registers and other state accordingly. (as we are done interacting with the Phy for this operation)
139  *       OR
140  *     * The Phy asks us to reevaluate if we want to abort. In this case, we hold responding to the Phy
141  *       and instead set the Timer_RADIO_abort_reeval to the time in which we need to respond to the Phy
142  *       and let time pass until that microsecond is ended.
143  *       At that point in time:
144  *          * If SW (or whatever else may trigger a TASK) has caused the procedure to end, we tell the Phy
145  *            we are aborting right now
146  *          * If nothing stopped it yet, we respond with a new abort reevaluation time in the future to the Phy,
147  *            and continue from (1).
148  *       The idea is that Timer_RADIO_abort_reeval is a separate timer that runs in parallel to the main Timer_RADIO and any other
149  *       HW event timer. And as Timer_RADIO_abort_reeval is the last timer scheduled by the HW_model_top in a given time, we will know if
150  *       anything else has affected the RADIO state in a way that requires us to stop the interaction with the Phy or not.
151  *   When we receive the CCA end from the Phy, we will also check the result, set registers accordingly, and pre-set the cca_status so
152  *   as to raise or not the CCABUSY/IDLE signals.
153  *   For an Rx it is marginally more complex, as we not only receive the end (either no sync, or crcok/failed), but also an intermediate
154  *   notification when the address has been received. At this point (address end) we pre-check some of the packet content (address for BLE adv,
155  *   length, etc) and already set some status registers and make some decisions about if we should proceed with the packet or not.
156  *
157  *   The CCA and ED procedures are so similar that they are handled with the same CCA_ED state in the main state machine,
158  *   most of the same CCA_ED code, and the same CCA procedure to the Phy.
159  */
160 
161 NRF_RADIO_Type NRF_RADIO_regs;
162 uint32_t NRF_RADIO_INTEN = 0; //interrupt enable (global for RADIO_signals.c)
163 
164 bs_time_t Timer_RADIO = TIME_NEVER; //main radio timer
165 bs_time_t Timer_RADIO_abort_reeval = TIME_NEVER; //Abort reevaluation response timer, this timer must have the lowest priority of all events (which may cause an abort)
166 
167 static TIFS_state_t TIFS_state = TIFS_DISABLE;
168 static bool TIFS_ToTxNotRx = false; //Are we in a TIFS automatically starting a Tx from a Rx (true), or Rx from Tx (false)
169 static bs_time_t Timer_TIFS = TIME_NEVER;
170 static bool from_hw_tifs = false; /* Unfortunate hack due to the SW racing the HW to clear SHORTS*/
171 
172 static RADIO_Rx_status_t rx_status;
173 static RADIO_Tx_status_t tx_status;
174 static RADIO_CCA_status_t cca_status;
175 
176 static double bits_per_us; //Bits per us for the ongoing Tx or Rx
177 
178 static bs_time_t next_recheck_time; // when we asked the phy to recheck (in our own time) next time
179 static abort_state_t abort_fsm_state = No_pending_abort_reeval; //This variable shall be set to Tx/Rx_Abort_reeval when the phy is waiting for an abort response (and in no other circumstance)
180 static int aborting_set = 0; //If set, we will abort the current Tx/Rx/CCA at the next abort reevaluation
181 
182 static nrfra_state_t radio_state;
183 static nrfra_sub_state_t radio_sub_state;
184 
185 static uint8_t tx_buf[_NRF_MAX_PACKET_SIZE]; //starting from the header, and including CRC
186 static uint8_t rx_buf[_NRF_MAX_PACKET_SIZE]; // "
187 static uint8_t *rx_pkt_buffer_ptr = (uint8_t*)&rx_buf;
188 
189 static bool radio_on = false;
190 
191 static bool rssi_sampling_on = false;
192 
193 static void start_Tx();
194 static void start_Rx();
195 static void start_CCA_ED(bool CCA_not_ED);
196 static void Rx_Addr_received();
197 static void Tx_abort_eval_respond();
198 static void Rx_abort_eval_respond();
199 static void CCA_abort_eval_respond();
200 static void nrf_radio_device_address_match();
201 
radio_reset()202 static void radio_reset() {
203   memset(&NRF_RADIO_regs, 0, sizeof(NRF_RADIO_regs));
204   radio_state = RAD_DISABLED;
205   NRF_RADIO_INTEN = 0;
206   radio_sub_state = SUB_STATE_INVALID;
207   Timer_RADIO = TIME_NEVER;
208   rssi_sampling_on = false;
209 
210   TIFS_state = TIFS_DISABLE;
211   TIFS_ToTxNotRx = false;
212   Timer_TIFS = TIME_NEVER;
213 
214   nrf_radio_bitcounter_reset();
215 
216   //Registers' reset values:
217   NRF_RADIO_regs.FREQUENCY = 0x00000002;
218   NRF_RADIO_regs.DATAWHITEIV = 0x00000040;
219   NRF_RADIO_regs.MODECNF0 = 0x00000200;
220   NRF_RADIO_regs.SFD = 0xA7;
221   NRF_RADIO_regs.CCACTRL = 0x052D0000;
222   NRF_RADIO_regs.CTEINLINECONF = 0x00002800;
223   NRF_RADIO_regs.DFECTRL1 = 0x00023282;
224   for (int i = 0; i < 8; i++)
225     NRF_RADIO_regs.PSEL.DFEGPIO[i] = 0xFFFFFFFF;
226   NRF_RADIO_regs.DFEPACKET.MAXCNT = 0x00001000;
227   NRF_RADIO_regs.POWER = 1;
228 }
229 
nrf_radio_init()230 void nrf_radio_init() {
231   nrfra_timings_init();
232   radio_reset();
233   radio_on = false;
234   bits_per_us = 1;
235 }
236 
nrf_radio_clean_up()237 void nrf_radio_clean_up() {
238   nrf_radio_bitcounter_cleanup();
239 }
240 
nrf_radio_get_bpus()241 double nrf_radio_get_bpus(){
242   return bits_per_us;
243 }
244 
nrfra_set_Timer_RADIO(bs_time_t t)245 static inline void nrfra_set_Timer_RADIO(bs_time_t t){
246   Timer_RADIO = t;
247   nrf_hw_find_next_timer_to_trigger();
248 }
249 
nrfra_set_Timer_abort_reeval(bs_time_t t)250 static inline void nrfra_set_Timer_abort_reeval(bs_time_t t){
251   Timer_RADIO_abort_reeval = t;
252   nrf_hw_find_next_timer_to_trigger();
253 }
254 
nrf_radio_tasks_TXEN()255 void nrf_radio_tasks_TXEN() {
256   if ( ( radio_state != RAD_DISABLED )
257       && ( radio_state != RAD_TXIDLE )
258       && ( radio_state != RAD_RXIDLE ) ){
259     bs_trace_warning_line_time(
260         "NRF_RADIO: TXEN received when the radio was not DISABLED or TX/RXIDLE but in state %i. It will be ignored. Expect problems\n",
261         radio_state);
262     return;
263   }
264   TIFS_state = TIFS_DISABLE;
265   radio_state = RAD_TXRU;
266   NRF_RADIO_regs.STATE = RAD_TXRU;
267 
268   nrfra_set_Timer_RADIO(tm_get_hw_time() + nrfra_timings_get_rampup_time(1, from_hw_tifs));
269 }
270 
nrf_radio_tasks_RXEN()271 void nrf_radio_tasks_RXEN() {
272   if ( ( radio_state != RAD_DISABLED )
273       && ( radio_state != RAD_TXIDLE )
274       && ( radio_state != RAD_RXIDLE ) ){
275     bs_trace_warning_line_time(
276         "NRF_RADIO: RXEN received when the radio was not DISABLED or TX/RXIDLE but in state %i. It will be ignored. Expect problems\n",
277         radio_state);
278     return;
279   }
280   TIFS_state = TIFS_DISABLE;
281   radio_state = RAD_RXRU;
282   NRF_RADIO_regs.STATE = RAD_RXRU;
283   nrfra_set_Timer_RADIO(tm_get_hw_time() + nrfra_timings_get_rampup_time(0, from_hw_tifs));
284 }
285 
abort_if_needed()286 static void abort_if_needed(){
287   if ( ( abort_fsm_state == Tx_Abort_reeval )
288       || ( abort_fsm_state == Rx_Abort_reeval )
289       || ( abort_fsm_state == CCA_Abort_reeval ) ){
290     //If the phy is waiting for a response from us, we need to tell it, that we are aborting whatever it was doing
291     aborting_set = 1;
292   }
293   if ( radio_sub_state == RX_WAIT_FOR_ADDRESS_END ){
294     //we answer immediately to the phy rejecting the packet
295     p2G4_dev_rxv2_cont_after_addr_nc_b(false, NULL);
296     radio_sub_state = SUB_STATE_INVALID;
297   }
298 }
299 
nrf_radio_tasks_START()300 void nrf_radio_tasks_START () {
301   if ( radio_state == RAD_TXIDLE ) {
302     start_Tx();
303   } else if ( radio_state == RAD_RXIDLE ) {
304     start_Rx();
305   } else {
306     bs_trace_warning_line_time(
307         "NRF_RADIO: TASK_START received while the radio was not in either TXIDLE or RXIDLE but in state %i. It will be ignored => expect problems\n",
308         radio_state);
309   }
310 }
311 
nrf_radio_tasks_CCASTART()312 void nrf_radio_tasks_CCASTART() {
313   if ((radio_state != RAD_RXIDLE)){
314     bs_trace_warning_line_time(
315         "NRF_RADIO: CCASTART received when the radio was not RXIDLE but in state %i. "
316         "It will be ignored. Expect problems\n",
317         radio_state);
318     return;
319   }
320   start_CCA_ED(1);
321 }
322 
nrf_radio_tasks_CCASTOP()323 void nrf_radio_tasks_CCASTOP() {
324   if (( radio_state == RAD_CCA_ED ) && ( cca_status.CCA_notED )) {
325     abort_if_needed();
326     radio_state = RAD_RXIDLE;
327     NRF_RADIO_regs.STATE = RAD_RXIDLE;
328     nrfra_set_Timer_RADIO(TIME_NEVER);
329     nrf_radio_signal_CCASTOPPED();
330   } else {
331     bs_trace_info_line_time(3,
332         "NRF_RADIO: TASK_CCASTOP received while the radio was not on a CCA procedure (was %i, %i). "
333         "It will be ignored\n",
334         radio_state, cca_status.CCA_notED);
335   }
336 }
337 
nrf_radio_tasks_EDSTART()338 void nrf_radio_tasks_EDSTART() {
339   if ((radio_state != RAD_RXIDLE)){
340     bs_trace_warning_line_time(
341         "NRF_RADIO: EDSTART received when the radio was not RXIDLE but in state %i. "
342         "It will be ignored. Expect problems\n",
343         radio_state);
344     return;
345   }
346   start_CCA_ED(0);
347 }
348 
nrf_radio_tasks_EDSTOP()349 void nrf_radio_tasks_EDSTOP() {
350   if (( radio_state == RAD_CCA_ED ) && ( cca_status.CCA_notED == 0)) {
351     abort_if_needed();
352     radio_state = RAD_RXIDLE;
353     NRF_RADIO_regs.STATE = RAD_RXIDLE;
354     nrfra_set_Timer_RADIO(TIME_NEVER);
355     nrf_radio_signal_EDSTOPPED();
356   } else {
357     bs_trace_info_line_time(3,
358         "NRF_RADIO: TASK_EDSTOP received while the radio was not on a ED procedure (was %i, %i). "
359         "It will be ignored\n",
360         radio_state, cca_status.CCA_notED);
361   }
362 }
363 
nrf_radio_tasks_STOP()364 void nrf_radio_tasks_STOP(){
365   nrf_radio_stop_bit_counter();
366 
367   if ( radio_state == RAD_TX ){
368     abort_if_needed();
369     radio_state = RAD_TXIDLE;
370     NRF_RADIO_regs.STATE = RAD_TXIDLE;
371     nrfra_set_Timer_RADIO(TIME_NEVER);
372   } else if ( radio_state == RAD_RX ){
373     abort_if_needed();
374     radio_state = RAD_RXIDLE;
375     NRF_RADIO_regs.STATE = RAD_RXIDLE;
376     nrfra_set_Timer_RADIO(TIME_NEVER);
377   } else if ( radio_state == RAD_CCA_ED ){
378     //The documentation is not clear about what happens if we get a STOP during a CCA or ED procedure,
379     //but it seems for CCA it can cause a bit of a mess depending on CCA mode.
380     //the behavior here is that we stop just like if it was an active Rx, and do *not* trigger a CCASTOPPED or EDSTOPPED event
381     bs_trace_warning_line_time(
382         "NRF_RADIO: TASK_STOP received while the radio was performing a CCA or ED procedure. "
383         "In this models we stop the procedure, but this can cause a mess in real HW\n");
384     abort_if_needed();
385     radio_state = RAD_RXIDLE;
386     NRF_RADIO_regs.STATE = RAD_RXIDLE;
387     nrfra_set_Timer_RADIO(TIME_NEVER);
388   } else {
389     bs_trace_warning_line_time(
390         "NRF_RADIO: TASK_STOP received while the radio was not on either TX or RX but in state %i. "
391         "It will be ignored\n",
392         radio_state);
393   }
394 }
395 
nrf_radio_tasks_DISABLE()396 void nrf_radio_tasks_DISABLE() {
397   nrf_radio_stop_bit_counter();
398 
399   if ( radio_state == RAD_TX ){
400     abort_if_needed();
401     radio_state = RAD_TXIDLE; //Momentary (will be changedin the if below)
402     NRF_RADIO_regs.STATE = RAD_TXIDLE;
403   } else if ( radio_state == RAD_RX ){
404     abort_if_needed();
405     radio_state = RAD_RXIDLE; //Momentary (will be changed in the if below)
406     NRF_RADIO_regs.STATE = RAD_RXIDLE;
407   } else if ( radio_state == RAD_CCA_ED ){
408     //The documentation is not clear about what happens if we get a disable during a CCA  or ED procedure,
409     //the assumption here is that we stop just like if it was an active Rx, but do not trigger a CCASTOPPED or EDSTOPPED event
410     abort_if_needed();
411     radio_state = RAD_RXIDLE; //Momentary (will be changed in the if below)
412     NRF_RADIO_regs.STATE = RAD_RXIDLE;
413   }
414 
415   if (TIFS_state != TIFS_DISABLE) {
416     TIFS_state = TIFS_DISABLE;
417     nrfra_set_Timer_RADIO(TIME_NEVER);
418     Timer_TIFS = TIME_NEVER;
419   }
420 
421   if ( ( radio_state == RAD_TXRU ) || ( radio_state == RAD_TXIDLE ) ) {
422     radio_state = RAD_TXDISABLE;
423     NRF_RADIO_regs.STATE = RAD_TXDISABLE;
424     TIFS_state = TIFS_DISABLE;
425     nrfra_set_Timer_RADIO(tm_get_hw_time() + nrfra_timings_get_TX_rampdown_time());
426   } else if ( ( radio_state == RAD_RXRU ) || ( radio_state == RAD_RXIDLE ) ) {
427     radio_state = RAD_RXDISABLE;
428     NRF_RADIO_regs.STATE = RAD_RXDISABLE;
429     TIFS_state = TIFS_DISABLE;
430     nrfra_set_Timer_RADIO(tm_get_hw_time() + nrfra_timings_get_RX_rampdown_time());
431   } else if ( radio_state == RAD_DISABLED ) {
432     //It seems the radio will also signal a DISABLED event even if it was already disabled
433     nrf_radio_stop_bit_counter();
434     nrf_radio_signal_DISABLED();
435   }
436 }
437 
nrf_radio_tasks_RSSISTART()438 void nrf_radio_tasks_RSSISTART () {
439   rssi_sampling_on = true;
440 }
441 
nrf_radio_tasks_RSSISTOP()442 void nrf_radio_tasks_RSSISTOP(){
443   rssi_sampling_on = false;
444 }
445 
nrf_radio_regw_sideeffects_INTENSET()446 void nrf_radio_regw_sideeffects_INTENSET(){
447   if ( NRF_RADIO_regs.INTENSET ){
448     NRF_RADIO_INTEN |= NRF_RADIO_regs.INTENSET;
449     NRF_RADIO_regs.INTENSET = NRF_RADIO_INTEN;
450   }
451 }
452 
nrf_radio_regw_sideeffects_INTENCLR()453 void nrf_radio_regw_sideeffects_INTENCLR(){
454   if ( NRF_RADIO_regs.INTENCLR ){
455     NRF_RADIO_INTEN  &= ~NRF_RADIO_regs.INTENCLR;
456     NRF_RADIO_regs.INTENSET = NRF_RADIO_INTEN;
457     NRF_RADIO_regs.INTENCLR = 0;
458   }
459 }
460 
nrf_radio_regw_sideeffects_POWER()461 void nrf_radio_regw_sideeffects_POWER(){
462   if ( NRF_RADIO_regs.POWER == 0 ){
463     radio_on = false;
464   } else {
465     if ( radio_on == false ){
466       radio_on = true;
467       abort_if_needed();
468       radio_reset();
469       nrf_hw_find_next_timer_to_trigger();
470     }
471   }
472 }
473 
474 /**
475  * This is a fake task meant to start a HW timer for the TX->RX or RX->TX TIFS
476  */
nrf_radio_fake_task_TRXEN_TIFS()477 void nrf_radio_fake_task_TRXEN_TIFS(){
478   if ( TIFS_state == TIFS_WAITING_FOR_DISABLE ) {
479     TIFS_state = TIFS_TRIGGERING_TRX_EN;
480     nrfra_set_Timer_RADIO(Timer_TIFS);
481     if ( Timer_RADIO < tm_get_hw_time() ){
482       bs_trace_warning_line_time("NRF_RADIO: TIFS Ups: The Ramp down from Rx/Tx into a Tx/Rx takes more than the programmed TIFS time\n");
483     }
484   }
485 }
486 
487 /**
488  * If the HW automatic TIFS switch is enabled, prepare the internals for an automatic switch
489  * (when a fake_task_TRXEN_TIFS is automatically triggered after a disable due to a shortcut)
490  * otherwise do nothing
491  *
492  * Input Tx_Not_Rx: Are we finishing a Tx (true) or an Rx (false)
493  */
maybe_prepare_TIFS(bool Tx_Not_Rx)494 void maybe_prepare_TIFS(bool Tx_Not_Rx){
495   bs_time_t delta;
496   if ( !nrfra_is_HW_TIFS_enabled() ) {
497     return;
498   }
499   if ( NRF_RADIO_regs.SHORTS & RADIO_SHORTS_DISABLED_TXEN_Msk ){
500     TIFS_ToTxNotRx = true;
501   } else {
502     TIFS_ToTxNotRx = false;
503   }
504 
505   if ( Tx_Not_Rx ){ //End of Tx
506     delta = NRF_RADIO_regs.TIFS + nrfra_timings_get_TX_chain_delay() - nrfra_timings_get_rampup_time(0, 1) - 3; /*open slightly earlier to have jitter margin*/
507   } else { //End of Rx
508     delta = NRF_RADIO_regs.TIFS - nrfra_timings_get_Rx_chain_delay() - nrfra_timings_get_TX_chain_delay() - nrfra_timings_get_rampup_time(1, 1) + 1;
509   }
510   Timer_TIFS = tm_get_hw_time() + delta;
511   TIFS_state = TIFS_WAITING_FOR_DISABLE;
512 }
513 
514 /**
515  * The main radio timer (Timer_RADIO) has just triggered,
516  * continue whatever activity we are on
517  * (typically do something at the end/start of a state, set the new state
518  * and schedule further the next state change)
519  */
nrf_radio_timer_triggered()520 void nrf_radio_timer_triggered(){
521   if ( radio_state == RAD_TXRU ){
522     radio_state = RAD_TXIDLE;
523     NRF_RADIO_regs.STATE = RAD_TXIDLE;
524     nrfra_set_Timer_RADIO(TIME_NEVER);
525     nrf_radio_signal_READY();
526     nrf_radio_signal_TXREADY();
527   } else if ( radio_state == RAD_RXRU ){
528     radio_state = RAD_RXIDLE;
529     NRF_RADIO_regs.STATE = RAD_RXIDLE;
530     nrfra_set_Timer_RADIO(TIME_NEVER);
531     nrf_radio_signal_READY();
532     nrf_radio_signal_RXREADY();
533   } else if ( radio_state == RAD_TX ){
534     if ( radio_sub_state == TX_WAIT_FOR_ADDRESS_END ){
535       radio_sub_state = TX_WAIT_FOR_PAYLOAD_END;
536       nrfra_set_Timer_RADIO(tx_status.PAYLOAD_end_time);
537       nrf_radio_signal_ADDRESS();
538       nrf_radio_signal_FRAMESTART(); //See note on FRAMESTART
539     } else if ( radio_sub_state == TX_WAIT_FOR_PAYLOAD_END ) {
540       radio_sub_state = TX_WAIT_FOR_CRC_END;
541       nrfra_set_Timer_RADIO(tx_status.CRC_end_time);
542       nrf_radio_signal_PAYLOAD();
543     } else if ( radio_sub_state == TX_WAIT_FOR_CRC_END ) {
544       radio_sub_state = SUB_STATE_INVALID;
545       radio_state = RAD_TXIDLE;
546       NRF_RADIO_regs.STATE = RAD_TXIDLE;
547       nrfra_set_Timer_RADIO(TIME_NEVER);
548       nrf_radio_stop_bit_counter();
549       nrf_radio_signal_END();
550       nrf_radio_signal_PHYEND(); //See note on EVENTS_PHYEND
551       maybe_prepare_TIFS(true);
552     }  else { //SUB_STATE_INVALID
553       bs_trace_error_time_line("programming error\n");
554     }
555   } else if ( radio_state == RAD_RX ){
556     if ( radio_sub_state == RX_WAIT_FOR_ADDRESS_END ) {
557       nrfra_set_Timer_RADIO(TIME_NEVER);
558       nrf_hw_find_next_timer_to_trigger();
559       nrf_radio_signal_SYNC(); //See note on EVENTS_SYNC
560       nrf_radio_signal_ADDRESS();
561       nrf_radio_signal_FRAMESTART(); //See note on FRAMESTART
562       Rx_Addr_received();
563       radio_sub_state = RX_WAIT_FOR_PAYLOAD_END;
564       nrfra_set_Timer_RADIO(rx_status.PAYLOAD_End_Time);
565     } else if ( radio_sub_state == RX_WAIT_FOR_PAYLOAD_END ) {
566       radio_sub_state = RX_WAIT_FOR_CRC_END;
567       nrfra_set_Timer_RADIO(rx_status.CRC_End_Time);
568       nrf_radio_signal_PAYLOAD();
569     } else if ( radio_sub_state == RX_WAIT_FOR_CRC_END ) {
570       radio_sub_state = SUB_STATE_INVALID;
571       radio_state = RAD_RXIDLE;
572       NRF_RADIO_regs.STATE = RAD_RXIDLE;
573       nrfra_set_Timer_RADIO(TIME_NEVER);
574       if ( rx_status.CRC_OK ) {
575         nrf_radio_signal_CRCOK();
576       } else {
577         nrf_radio_signal_CRCERROR();
578       }
579       nrf_radio_stop_bit_counter();
580       nrf_radio_signal_PHYEND(); //See note on EVENTS_PHYEND
581       nrf_radio_signal_END();
582       maybe_prepare_TIFS(false);
583     } else { //SUB_STATE_INVALID
584       bs_trace_error_time_line("programming error\n");
585     }
586   } else if ( radio_state == RAD_CCA_ED ){
587     radio_state = RAD_RXIDLE;
588     NRF_RADIO_regs.STATE = RAD_RXIDLE;
589     nrfra_set_Timer_RADIO(TIME_NEVER);
590     if (cca_status.CCA_notED) { //CCA procedure ended
591       if (cca_status.is_busy) {
592         nrf_radio_signal_CCABUSY();
593       } else {
594         nrf_radio_signal_CCAIDLE();
595       }
596     } else { //ED procedure ended
597       nrf_radio_signal_EDEND();
598     }
599   } else if ( radio_state == RAD_TXDISABLE ){
600     radio_state = RAD_DISABLED;
601     NRF_RADIO_regs.STATE = RAD_DISABLED;
602     nrfra_set_Timer_RADIO(TIME_NEVER);
603     nrf_radio_stop_bit_counter();
604     nrf_radio_signal_DISABLED();
605   } else if ( radio_state == RAD_RXDISABLE ){
606     radio_state = RAD_DISABLED;
607     NRF_RADIO_regs.STATE = RAD_DISABLED;
608     nrfra_set_Timer_RADIO(TIME_NEVER);
609     nrf_radio_stop_bit_counter();
610     nrf_radio_signal_DISABLED();
611   } else {
612     if ( ( radio_state == RAD_DISABLED ) && ( TIFS_state == TIFS_TRIGGERING_TRX_EN ) ) {
613       if ( Timer_RADIO != Timer_TIFS ){
614         bs_trace_warning_line_time("NRF_RADIO: TIFS Ups 3\n");
615       }
616       TIFS_state = TIFS_DISABLE;
617       nrfra_set_Timer_RADIO(TIME_NEVER);
618       from_hw_tifs = true;
619       if ( TIFS_ToTxNotRx ) {
620         nrf_radio_tasks_TXEN();
621       } else {
622         nrf_radio_tasks_RXEN();
623       }
624       from_hw_tifs = false;
625     } else {
626       bs_trace_error_line_time(
627           "NRF_RADIO: this should not have happened (radio_state =%i)\n",
628           radio_state);
629     }
630   }
631 }
632 
633 /**
634  * The abort reevaluation timer has just triggered,
635  * => we can now respond to the Phy with our abort decision
636  */
nrf_radio_timer_abort_reeval_triggered()637 void nrf_radio_timer_abort_reeval_triggered(){
638   nrfra_set_Timer_abort_reeval(TIME_NEVER);
639 
640   if ( abort_fsm_state == Tx_Abort_reeval ){
641     abort_fsm_state = No_pending_abort_reeval;
642     Tx_abort_eval_respond();
643   } else if ( abort_fsm_state == Rx_Abort_reeval ) {
644     abort_fsm_state = No_pending_abort_reeval;
645     Rx_abort_eval_respond();
646   } else if ( abort_fsm_state == CCA_Abort_reeval ) {
647     abort_fsm_state = No_pending_abort_reeval;
648     CCA_abort_eval_respond();
649   } else {
650     bs_trace_error_line("The abort timer was left running.. somebody forgot to cleanup..\n");
651   }
652 }
653 
654 /**
655  * Handle all possible responses to a Tx request from the Phy
656  */
handle_Tx_response(int ret)657 static void handle_Tx_response(int ret){
658   if (ret == -1){
659     bs_trace_raw_manual_time(3,tm_get_abs_time(),"The phy disconnected us during a Tx\n");
660     hwll_disconnect_phy_and_exit();
661   } else if ( ret == P2G4_MSG_TX_END  ) {
662     bs_time_t end_time = hwll_dev_time_from_phy(tx_status.tx_resp.end_time);
663     tm_update_last_phy_sync_time( end_time );
664     //The main machine was already pre-programmed at the Tx Start, no need to do anything else now
665   } else if ( ret == P2G4_MSG_ABORTREEVAL ) {
666     tm_update_last_phy_sync_time( next_recheck_time );
667     abort_fsm_state = Tx_Abort_reeval;
668     nrfra_set_Timer_abort_reeval(next_recheck_time);
669   }
670 }
671 
672 /**
673  * Set the Phy abort structure to the next time we will want to either abort or have a recheck
674  * And store in next_recheck_time the next recheck time
675  */
update_abort_struct(p2G4_abort_t * abort,bs_time_t * next_recheck_time)676 static void update_abort_struct(p2G4_abort_t *abort, bs_time_t *next_recheck_time){
677   //We will want to recheck next time anything may decide to stop the radio, that can be SW or HW
678   //The only logical way to do so is to set it to the next timer whatever it may be as many can trigger SW interrupts
679   *next_recheck_time = tm_get_next_timer_abstime();
680   abort->recheck_time = hwll_phy_time_from_dev(*next_recheck_time);
681 
682   //We either have decided already we want to abort so we do it right now
683   //or we have not decided yet
684   if ( aborting_set == 1 ) {
685     aborting_set = 0; //By returning tm_get_abs_time(), we are aborting right now
686     abort->abort_time = hwll_phy_time_from_dev(tm_get_abs_time());
687   } else {
688     abort->abort_time = TIME_NEVER;
689   }
690 }
691 
692 /**
693  * We have reached the time in which we wanted to reevaluate if we would abort or not
694  * so we answer to the Phy with our decision
695  */
Tx_abort_eval_respond()696 static void Tx_abort_eval_respond(){
697   //The abort must have been evaluated by now so we can respond to the waiting phy
698   p2G4_abort_t *abort = &tx_status.tx_req.abort;
699 
700   update_abort_struct(abort, &next_recheck_time);
701 
702   int ret = p2G4_dev_provide_new_tx_abort_nc_b(abort);
703 
704   handle_Tx_response(ret);
705 }
706 
707 /*
708  * Actually start the Tx in this microsecond (+ the Tx chain delay in the Phy)
709  */
start_Tx()710 static void start_Tx(){
711 
712   radio_state = RAD_TX;
713   NRF_RADIO_regs.STATE = RAD_TX;
714 
715   nrfra_check_packet_conf();
716 
717   //TOLOW: Add support for other packet formats and bitrates
718   uint8_t preamble_len;
719   uint8_t address_len;
720   uint8_t header_len;
721   uint payload_len;
722   //Note: I assume in Tx the length is always < PCNF1.MAXLEN and that STATLEN is always 0 (otherwise add a check)
723   uint8_t crc_len = nrfra_get_crc_length();
724 
725   if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_1Mbit) {
726     preamble_len = 1; //1 byte
727     address_len = 4;
728     header_len  = 2;
729     bits_per_us = 1;
730   } else if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_2Mbit) {
731     preamble_len = 2; //2 bytes
732     address_len = 4;
733     header_len  = 2;
734     bits_per_us = 2;
735   } else if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ieee802154_250Kbit) {
736     preamble_len = 4;
737     address_len = 1;
738     header_len  = 1;
739     bits_per_us = 0.25;
740   }
741 
742   payload_len = nrfra_tx_copy_payload(tx_buf);
743 
744   /* This code should be generalized to support any CRC configuration (CRCCNF, CRCINIT AND CRCPOLY)
745    * When doing so, we should still calculate the ble and 154 crc's with their optimized table implementations
746    * Here we just assume the CRC is configured as it should given the modulation */
747   uint32_t crc_init = NRF_RADIO_regs.CRCINIT & RADIO_CRCINIT_CRCINIT_Msk;
748   if ((NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_1Mbit)
749      || (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_2Mbit) ) {
750     append_crc_ble(tx_buf, header_len + payload_len, crc_init);
751   } else if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ieee802154_250Kbit) {
752     //15.4 does not CRC the length (header) field
753     append_crc_154(&tx_buf[header_len], payload_len, crc_init);
754   }
755 
756   bs_time_t packet_duration; //From preamble to CRC
757   packet_duration  = preamble_len*8 + address_len*8;
758   packet_duration += header_len*8 + payload_len*8 + crc_len*8;
759   packet_duration /= bits_per_us;
760   uint packet_size = header_len + payload_len + crc_len;
761 
762   nrfra_prep_tx_request(&tx_status.tx_req, packet_size, packet_duration);
763 
764   update_abort_struct(&tx_status.tx_req.abort, &next_recheck_time);
765 
766   //Request the Tx from the Phy:
767   int ret = p2G4_dev_req_txv2_nc_b(&tx_status.tx_req, tx_buf,  &tx_status.tx_resp);
768   handle_Tx_response(ret);
769 
770   tx_status.ADDRESS_end_time = tm_get_hw_time() + (bs_time_t)((preamble_len*8 + address_len*8)/bits_per_us);
771   tx_status.PAYLOAD_end_time = tx_status.ADDRESS_end_time + (bs_time_t)(8*(header_len + payload_len)/bits_per_us);
772   tx_status.CRC_end_time = tx_status.PAYLOAD_end_time + (bs_time_t)(crc_len*8/bits_per_us);
773 
774   radio_sub_state = TX_WAIT_FOR_ADDRESS_END;
775   nrfra_set_Timer_RADIO(tx_status.ADDRESS_end_time);
776 }
777 
778 
Rx_handle_end_response(bs_time_t end_time)779 static void Rx_handle_end_response(bs_time_t end_time) {
780 
781   if (rx_status.rx_resp.status != P2G4_RXSTATUS_HEADER_ERROR) {
782       rx_status.CRC_End_Time = end_time + nrfra_timings_get_Rx_chain_delay();
783   } //Otherwise we do not really now how the Nordic RADIO behaves depending on
784   //where the biterrors are and so forth. So let's always behave like if the
785   //packet lenght was received correctly, and just report a CRC error at the
786   //end of the CRC
787 
788   uint payload_len = nrfra_get_payload_length(rx_buf);
789   uint crc_len = nrfra_get_crc_length();
790 
791   if ( rx_status.rx_resp.status == P2G4_RXSTATUS_OK ){
792     //Let's copy the CRC
793     uint32_t crc = 0;
794     //Eventually this should be generalized with the packet configuration
795     if (((NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_1Mbit)
796         || (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_2Mbit))
797         && ( rx_status.rx_resp.packet_size >= 5 ) ){
798       memcpy((void*)&crc, &rx_buf[2 + payload_len], crc_len);
799     } else if ((NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ieee802154_250Kbit)
800         && ( rx_status.rx_resp.packet_size >= 3 ) ){
801       memcpy((void*)&crc, &rx_buf[1 + payload_len], crc_len);
802     }
803 
804     NRF_RADIO_regs.RXCRC = crc;
805     rx_status.CRC_OK = 1;
806     NRF_RADIO_regs.CRCSTATUS = 1;
807   }
808 
809   nrf_ccm_radio_received_packet(!rx_status.CRC_OK);
810 }
811 
812 
Rx_handle_address_end_response(bs_time_t address_time)813 static void Rx_handle_address_end_response(bs_time_t address_time) {
814 
815   rx_status.ADDRESS_End_Time = address_time + nrfra_timings_get_Rx_chain_delay();
816 
817   uint length = nrfra_get_payload_length(rx_buf);
818   uint max_length = (NRF_RADIO_regs.PCNF1 & NFCT_MAXLEN_MAXLEN_Msk) >> NFCT_MAXLEN_MAXLEN_Pos;
819 
820   if (length > max_length){
821     bs_trace_error_time_line("NRF_RADIO: received a packet longer than the configured max lenght (%i>%i), this is not yet handled in this models. I stop before it gets confusing\n", length, max_length);
822     length  = max_length;
823     //TODO: check packet length. If too long the packet should be truncated and not accepted from the phy, [we already have it in the buffer and we will have a CRC error anyhow. And we cannot let the phy run for longer than we will]
824   } else {
825     //NRF_RADIO_regs.PDUSTAT = 0; //TODO, set if greater
826   }
827 
828   //TODO: Discard Ieee802154_250Kbit frames with length == 0
829 
830   rx_status.packet_rejected = false;
831 
832   bs_time_t payload_end;
833 
834   if ((NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_1Mbit)
835       || (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_2Mbit)) {
836     payload_end = rx_status.rx_resp.rx_time_stamp + (bs_time_t)((2+length)*8/bits_per_us);
837   } else if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ieee802154_250Kbit) {
838     payload_end = rx_status.rx_resp.rx_time_stamp + (bs_time_t)((1+length)*8/bits_per_us);
839   } //Eventually this should be generalized with the packet configuration
840 
841   rx_status.PAYLOAD_End_Time = nrfra_timings_get_Rx_chain_delay() +
842                                hwll_dev_time_from_phy(payload_end);
843 
844   rx_status.CRC_End_Time = rx_status.PAYLOAD_End_Time + rx_status.CRC_duration; //Provisional value
845 
846   //Copy the whole packet (S0, lenght, S1 & payload) excluding the CRC.
847   if ((NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_1Mbit)
848       || (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_2Mbit)) {
849     if (rx_status.rx_resp.packet_size >= 5) { /*At least the header and CRC, otherwise better to not try to copy it*/
850       ((uint8_t*)NRF_RADIO_regs.PACKETPTR)[0] = rx_buf[0];
851       ((uint8_t*)NRF_RADIO_regs.PACKETPTR)[1] = rx_buf[1];
852       /* We cheat a bit and copy the whole packet already (The AAR block will look in Adv packets after 64 bits)*/
853       memcpy(&((uint8_t*)NRF_RADIO_regs.PACKETPTR)[2 + rx_status.S1Offset],
854           &rx_buf[2] , length);
855     }
856   } else if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ieee802154_250Kbit) {
857     if (rx_status.rx_resp.packet_size >= 3) { /*At least the header and CRC, otherwise better to not try to copy it*/
858             ((uint8_t*)NRF_RADIO_regs.PACKETPTR)[0] = rx_buf[0];
859             memcpy(&((uint8_t*)NRF_RADIO_regs.PACKETPTR)[1 + rx_status.S1Offset],
860                 &rx_buf[1] , length);
861           }
862   } //Eventually this should be generalized with the packet configuration
863 
864   if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ieee802154_250Kbit) {
865     //The real HW only copies the LQI value after the payload in this mode
866     //Note that doing it this early is a cheat
867     double RSSI = p2G4_RSSI_value_to_dBm(rx_status.rx_resp.rssi.RSSI);
868     uint8_t LQI = nrfra_dBm_to_modem_LQIformat(RSSI);
869     //Eventually this should be generalized with the packet configuration:
870     ((uint8_t*)NRF_RADIO_regs.PACKETPTR)[1 + rx_status.S1Offset + length] = LQI;
871   }
872 
873 }
874 
875 /**
876  * Handle all possible responses from the phy to a Rx request
877  */
handle_Rx_response(int ret)878 static void handle_Rx_response(int ret){
879   if ( ret == -1 ){
880     bs_trace_raw_manual_time(3,tm_get_abs_time(),"Communication with the phy closed during Rx\n");
881     hwll_disconnect_phy_and_exit();
882 
883   } else if ( ret == P2G4_MSG_ABORTREEVAL ) {
884 
885     tm_update_last_phy_sync_time( next_recheck_time );
886     abort_fsm_state = Rx_Abort_reeval;
887     nrfra_set_Timer_abort_reeval( BS_MAX(next_recheck_time,tm_get_abs_time()) );
888 
889   } else if ( ( ret == P2G4_MSG_RXV2_ADDRESSFOUND ) && ( radio_state == RAD_RX /*if we havent aborted*/ ) ) {
890 
891     bs_time_t address_time = hwll_dev_time_from_phy(rx_status.rx_resp.rx_time_stamp); //this is the end of the sync word in air time
892     tm_update_last_phy_sync_time(address_time);
893     Rx_handle_address_end_response(address_time);
894     radio_sub_state = RX_WAIT_FOR_ADDRESS_END;
895     nrfra_set_Timer_RADIO(rx_status.ADDRESS_End_Time);
896 
897   } else if ( ( ret == P2G4_MSG_RXV2_END ) && ( radio_state == RAD_RX /*if we havent aborted*/ ) ) {
898 
899     bs_time_t end_time = hwll_dev_time_from_phy(rx_status.rx_resp.end_time);
900     tm_update_last_phy_sync_time(end_time);
901     Rx_handle_end_response(end_time);
902   }
903 }
904 
905 /**
906  * We have reached the time in which we wanted to reevaluate if we would abort or not
907  * so we answer to the phy with our decision
908  */
Rx_abort_eval_respond()909 static void Rx_abort_eval_respond(){
910   //The abort must have been evaluated by now so we can respond to the waiting phy
911   p2G4_abort_t *abort = &rx_status.rx_req.abort;
912   update_abort_struct(abort, &next_recheck_time);
913 
914   int ret = p2G4_dev_provide_new_rxv2_abort_nc_b(abort);
915 
916   handle_Rx_response(ret);
917 }
918 
919 /*
920  * Actually start the Rx in this microsecond
921  */
start_Rx()922 static void start_Rx(){
923   #define RX_N_ADDR 8 /* How many addresses we can search in parallel */
924   p2G4_address_t rx_addresses[RX_N_ADDR];
925 
926   nrfra_check_packet_conf();
927 
928   radio_state = RAD_RX;
929   NRF_RADIO_regs.STATE = RAD_RX;
930   NRF_RADIO_regs.CRCSTATUS = 0;
931 
932   if ( NRF_RADIO_regs.PCNF0 & ( RADIO_PCNF0_S1INCL_Include << RADIO_PCNF0_S1INCL_Pos ) ){
933     rx_status.S1Offset = 1; /*1 byte offset in RAM (S1 length > 8 not supported)*/
934   } else {
935     rx_status.S1Offset = 0;
936   }
937 
938   if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_1Mbit) {
939     bits_per_us = 1;
940   } else if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_2Mbit) {
941     bits_per_us = 2;
942   } else if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ieee802154_250Kbit) {
943     bits_per_us = 0.25;
944   }
945   rx_status.CRC_duration = nrfra_get_crc_length()*8/bits_per_us;
946 
947   rx_status.CRC_OK = false;
948   rx_status.rx_resp.status = P2G4_RXSTATUS_NOSYNC;
949 
950   nrfra_prep_rx_request(&rx_status.rx_req, rx_addresses);
951 
952   update_abort_struct(&rx_status.rx_req.abort, &next_recheck_time);
953 
954   //attempt to receive
955   int ret = p2G4_dev_req_rxv2_nc_b(&rx_status.rx_req,
956       rx_addresses,
957       &rx_status.rx_resp,
958       &rx_pkt_buffer_ptr,
959       _NRF_MAX_PACKET_SIZE);
960 
961   radio_sub_state = SUB_STATE_INVALID;
962   nrfra_set_Timer_RADIO(TIME_NEVER);
963 
964   handle_Rx_response(ret);
965 }
966 
967 /**
968  * This function is called at the time when the Packet address would have been
969  * completely received
970  * (at the time of the end of the last bit of the packet address)
971  * To continue processing the reception (the Phy was left waiting for a response)
972  *
973  * Note that libPhyCom has already copied the whole packet into the input buffer
974  */
Rx_Addr_received()975 static void Rx_Addr_received(){
976 
977   bool accept_packet = !rx_status.packet_rejected;
978 
979   if ( rssi_sampling_on ){
980     NRF_RADIO_regs.RSSISAMPLE = nrfra_RSSI_value_to_modem_format(p2G4_RSSI_value_to_dBm(rx_status.rx_resp.rssi.RSSI));
981     nrf_radio_signal_RSSIEND();
982   }
983 
984   NRF_RADIO_regs.RXMATCH = 0; //The only we support so far
985 
986   if (NRF_RADIO_regs.DACNF & 0xFF) { /*If any of the addresses for device address match is enabled*/
987     /*
988      * NOTE: we cheat and we already check the advertisement addresses and
989      * raise the event, even though we should wait for 16 + 48 bits more
990      *
991      * If this is a problem, add a new timer and Rx state and delay raising the event
992      * until then
993      */
994     nrf_radio_device_address_match(rx_buf);
995   }
996 
997   update_abort_struct(&rx_status.rx_req.abort, &next_recheck_time);
998   int ret = p2G4_dev_rxv2_cont_after_addr_nc_b(accept_packet, &rx_status.rx_req.abort);
999 
1000   if ( accept_packet ){
1001     handle_Rx_response(ret);
1002   } else {
1003     //else We said we dont want to continue => there will be no response (ret==0 always). We just close the reception like if the phy finished on its own even though we finished it
1004   }
1005 }
1006 
1007 /**
1008  * Check if the address in the received (advertisement) packet
1009  * matches one configured in the DAP/DAB registers as set by DACNF
1010  *
1011  * If it does, it sets appropriately the DAI register,
1012  * in any case, it generates the DEVMATCH and DEVMISS signals accordingly
1013  *
1014  * Note that, as specified in the infocenter documentation,
1015  * the address is assumed to be the first 48 bits after the 2 byte header
1016  * and the TxAddr bit to be 7th bit in 1st header byte as per the BT Core spec.
1017  */
nrf_radio_device_address_match(uint8_t rx_buf[])1018 static void nrf_radio_device_address_match(uint8_t rx_buf[]) {
1019   bool match_found = false;
1020   bool nomatch;
1021   int TxAdd;
1022 
1023   for (int i = 0 ; i < 8; i++) {
1024     if (((NRF_RADIO_regs.DACNF >> i) & 1) == 0 ) {
1025       continue;
1026     }
1027 
1028     TxAdd = (NRF_RADIO_regs.DACNF >> (i + 8)) & 1;
1029 
1030     if (TxAdd != ((rx_buf[0] >> 6) & 1) ) {
1031       continue;
1032     }
1033 
1034     nomatch = (*(uint32_t *)(rx_buf + 2) != NRF_RADIO_regs.DAB[i]);
1035     uint32_t DAP = NRF_RADIO_regs.DAP[i] & UINT16_MAX;
1036     nomatch |= (*(uint16_t *)(rx_buf + 6) != DAP);
1037 
1038     if (nomatch) {
1039       continue;
1040     }
1041 
1042     match_found = true;
1043     NRF_RADIO_regs.DAI = i;
1044     break;
1045   }
1046 
1047   if (match_found) {
1048     nrf_radio_signal_DEVMATCH();
1049   } else {
1050     nrf_radio_signal_DEVMISS();
1051   }
1052 }
1053 
CCA_handle_end_response(void)1054 static void CCA_handle_end_response(void) {
1055   //Depending on mode, set status and registers
1056   //raising CCAIDLE, CCABUSY or EDEND will happen in the correct time in the main machine
1057 
1058   if (cca_status.CCA_notED) { //End a CCA procedure
1059     uint CCAMode = (NRF_RADIO_regs.CCACTRL & RADIO_CCACTRL_CCAMODE_Msk) >> RADIO_CCACTRL_CCAMODE_Pos;
1060 
1061     if ((CCAMode == RADIO_CCACTRL_CCAMODE_EdMode)
1062         || (CCAMode == RADIO_CCACTRL_CCAMODE_EdModeTest1)) {
1063       cca_status.is_busy = cca_status.cca_resp.rssi_overthreshold;
1064     } else if (CCAMode == RADIO_CCACTRL_CCAMODE_CarrierMode) {
1065       cca_status.is_busy = cca_status.cca_resp.mod_found;
1066     } else if (CCAMode == RADIO_CCACTRL_CCAMODE_CarrierAndEdMode) {
1067       cca_status.is_busy = cca_status.cca_resp.mod_found
1068           && cca_status.cca_resp.rssi_overthreshold;
1069     } else if (CCAMode == RADIO_CCACTRL_CCAMODE_CarrierOrEdMode) {
1070       cca_status.is_busy = cca_status.cca_resp.mod_found
1071           || cca_status.cca_resp.rssi_overthreshold;
1072     } else {
1073       bs_trace_error_time_line("%s, CCAMODE=%i suppport not yet implemented\n",
1074           __func__, CCAMode);
1075     }
1076   } else { // Ending an ED procedure
1077     double RSSI = p2G4_RSSI_value_to_dBm(cca_status.cca_resp.RSSI_max);
1078     NRF_RADIO_regs.EDSAMPLE = nrfra_dBm_to_modem_LQIformat(RSSI);
1079   }
1080 }
1081 
1082 /**
1083  * Handle all possible responses to a CCA request from the Phy
1084  */
handle_CCA_response(int ret)1085 static void handle_CCA_response(int ret){
1086   if (ret == -1){
1087     bs_trace_raw_manual_time(3,tm_get_abs_time(),"The Phy disconnected us during a CCA procedure\n");
1088     hwll_disconnect_phy_and_exit();
1089   } else if ( ret == P2G4_MSG_CCA_END  ) {
1090     bs_time_t end_time = hwll_dev_time_from_phy(cca_status.cca_resp.end_time);
1091     tm_update_last_phy_sync_time( end_time );
1092     cca_status.CCA_end_time = end_time;
1093     if (radio_state == RAD_CCA_ED) { /*if we haven't aborted*/
1094       nrfra_set_Timer_RADIO(cca_status.CCA_end_time);
1095     }
1096     CCA_handle_end_response();
1097   } else if ( ret == P2G4_MSG_ABORTREEVAL ) {
1098     tm_update_last_phy_sync_time( next_recheck_time );
1099     abort_fsm_state = CCA_Abort_reeval;
1100     nrfra_set_Timer_abort_reeval(next_recheck_time);
1101   }
1102 }
1103 
1104 /**
1105  * We have reached the time in which we wanted to reevaluate if we would abort or not
1106  * so we answer to the Phy with our decision
1107  */
CCA_abort_eval_respond()1108 static void CCA_abort_eval_respond(){
1109   //The abort must have been evaluated by now so we can respond to the waiting phy
1110   p2G4_abort_t *abort = &cca_status.cca_req.abort;
1111 
1112   update_abort_struct(abort, &next_recheck_time);
1113 
1114   int ret = p2G4_dev_provide_new_cca_abort_nc_b(abort);
1115 
1116   handle_CCA_response(ret);
1117 }
1118 
1119 /**
1120  * Start CCA or ED procedure right now.
1121  * input: CCA_not_ED = 1 for CCA, 0 for ED
1122  */
start_CCA_ED(bool CCA_not_ED)1123 static void start_CCA_ED(bool CCA_not_ED){
1124 
1125   radio_state = RAD_CCA_ED;
1126 
1127   cca_status.CCA_notED = CCA_not_ED;
1128   cca_status.is_busy = false;
1129 
1130   nrfra_prep_cca_request(&cca_status.cca_req, CCA_not_ED);
1131 
1132   update_abort_struct(&cca_status.cca_req.abort, &next_recheck_time);
1133 
1134   //Expected end time; note that it may be shorter if detect over threshold is set
1135   cca_status.CCA_end_time = tm_get_abs_time() + cca_status.cca_req.scan_duration;
1136   nrfra_set_Timer_RADIO(cca_status.CCA_end_time);
1137 
1138   //Request the CCA from the Phy:
1139   int ret = p2G4_dev_req_cca_nc_b(&cca_status.cca_req, &cca_status.cca_resp);
1140   handle_CCA_response(ret);
1141 }
1142