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
8 /**
9 * RADIO - 2.4 GHz Radio
10 * https://infocenter.nordicsemi.com/topic/ps_nrf52833/radio.html?cp=5_1_0_5_17
11 * https://infocenter.nordicsemi.com/topic/ps_nrf52833/radio.html?cp=5_1_0_5_17
12 *
13 * Note: as of now, only 1&2Mbps BLE & 15.4 packet formats are supported, there is quite many notes around in the code
14 * where changes would be required to support other formats. PCNF1.STATLEN is always assumed 0
15 *
16 * Note3: Only logical address 0 (in Tx or Rx) is supported
17 *
18 * Note4: only default freq. map supported
19 *
20 * Note5: Only little endian hosts supported (x86 is little endian)
21 *
22 * Note6.a: A RSSISTART task will be fully instantaneous (instead of taking ~0.25 micros)
23 * Note6.b: A RSSISTART task will (by now) use the latest RSSI sample from the Phy and not request a new one.
24 * If the stack is triggering this task to do a RSSI measurement without an actual packet reception
25 * the measurement will be wrong.
26 * Doing an immediate measurement requires an up to date libPhyCom and Phy. To avoid forcing users to update just for this, we postpone this feature.
27 * This feature should be enabled as soon as a Phy update is required for another reason.
28 * Note6.c: The spec says the radio must be actively receiving when receiving a RSSISTART task, but
29 * not what happens otherwise. The model just warns and uses the last value.
30 *
31 * 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)
32 *
33 * Note8: During idle nothing is sent to the air
34 *
35 * Note9: Double buffering of registers is not implemented. Changing the register during the packet Tx/Rx will cause trouble
36 * It should be (at least): PACKETPTR @ START
37 * MODE @ TXEN | RXEN
38 * CRC config @ START
39 *
40 * Note10: Regarding MAXLEN:
41 * if CRCINC==1, the CRC LEN is deducted from the length field, before MAXLEN is checked.
42 * This seems to be also the real HW behavior
43 * Bit errors in the length field reception, or even bit errors in the CI field reception (for Coded phy)
44 * are not accounted for when handling the length field in this model. The model will always
45 * act on the transmitted length field.
46 *
47 * Note11: Only the BLE & 15.4 CRC polynomials are supported
48 * 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
49 * On transmission we generate the correct CRC for correctness of the channel dump traces (and Ellisys traces)
50 * Note11b:The CRC configuration is directly deduced from the modulation, only BLE and 154 CRCs are supported so far
51 *
52 * Note12: * CCA or ED procedures cannot be performed while the RADIO is performing an actual packet reception (they are exclusive)
53 * * In CCA Mode2 & 3, this model (due to the Phy) does not search for a SFD, or for a correlation peak
54 * instead it searches for a compatible modulation of sufficient power (which is in line with what the 802.15.4
55 * standard specifies)
56 *
57 * Note13: Nothing related to AoA/AoD features (CTE, DFE) is implemented
58 *
59 * Note14: Several 52833 radio state change events are not yet implemented
60 * (EVENTS_MHRMATCH & EVENTS_CTEPRESENT)
61 *
62 * Note16: No antenna switching
63 *
64 * Note17: Interrupts are modeled as pulses to the NVIC, not level interrupts as they are in reality
65 *
66 * Note18: EVENTS_SYNC:
67 * a) It is not generated at the exact correct time:
68 * In this model it is generated at the end of the address (or SFD)
69 * while according to the infocenter spec this should come at the end of the preamble,
70 * and only if in coded and 15.4 mode.
71 * In reality it seems to come somewhere during the preamble for 15.4 and coded phy,
72 * and somewhere during the address for 1&2Mbps BLE.
73 * In any case this seems to be a debug signal, and a quite imprecise one,
74 * so the assumption is that nobody uses it for anything timing critical.
75 * b) it is only generated when there is a full address match. While in real HW this is not required
76 * (so false positives happen in real HW)
77 *
78 * Note19: EVENTS_PHYEND
79 * It is not generated at the exact correct time. In the model it is generated at the
80 * exact same time as END. While according to the spec, it should be generated with the last
81 * bit on *air* (That is the Tx chain delay later for Tx, and RxChainDelay earlier for Rx)
82 *
83 * Note20: The LQI value is based on a single measurement at the end of the SFD.
84 * While the real HW samples it in 3 places during the payload, and the middle one selected.
85 *
86 * Note21: Timings:
87 * * Radio ramp down time for 2Mbps BLE is 2 microseconds too long.
88 * * Many timings are simplified, and some events which take slightly different amounts of time to occur
89 * are produced at the same time as others, or so. Check NRF_RADIO_timings.c for some more notes.
90 *
91 * Note21.b: CodedPhy timings:
92 * * For CodedPhy the spec lacks radio timings, so the values used are mostly rounded
93 * versions of the ones the Zephyr controller used
94 * * At this point (for simplicity) The Rx chain delay for S=2 and S=8 are modeled as being equal.
95 * * It is quite unclear if the CRCOK/ERROR and PAYLOAD events are delayed by the equivalent
96 * of the conv. decoder taking 2 extra input bits or not, and if the ADDRESS event has an
97 * equivalent delay or not.
98 * At this point the model does not add a different delay to these, so this events
99 * timings should be considered a rough guess. CRCOK/ERROR is generated at the same time
100 * and the END event based on the end of TERM2.
101 *
102 * Note22: EVENTS_FRAMESTART
103 * * It is generated for all modulation types, this seems to be how the HW behaves even if the spec
104 * seems to mildly imply it is only for 15.4
105 * * In Tx: The spec seems unclear about the FRAMESTART being generated or not (after SHR).
106 * Drawings imply it is, the text that it does not. The HW does. The model does generate it after SHR.
107 * * In Rx: In the model it is generated at the SHR/SFD end (not PHR), meaning, at the same time as the ADDRESS EVENT
108 * The spec seems to contradict itself here. But seems in real HW it is generated at the end of the PHR.
109 *
110 * Note23: For nRF52/53: Powering off/on is not properly modeled (it is mostly ignored)
111 * (In the real setting POWER to 0, resets most registers. That is not the case in the models)
112 *
113 * Note24: Only PCNF1.ENDIAN == Little is supported (What BT and 802.15.4 use)
114 *
115 * Note25: The RATEBOOST event in real HW seems to be generated: only for Rx, only if the FEC2 block has S=2,
116 * and roughly at the end of TERM1. The models generates it at that point and only in that case.
117 * (It's timing is probably a bit off compared to real HW)
118 *
119 *
120 *
121 * Implementation Specification:
122 * A diagram of the main state machine can be found in docs/RADIO_states.svg
123 * That main state machine is driven by a timer (Timer_RADIO) which results in calls to nhw_radio_timer_triggered()
124 * and the tasks which cause transitions and/or the timer to be set to a new value.
125 *
126 * Apart from this main state machine there is a small state machine for handling the automatic TIFS re-enabling.
127 * See TIFS_state, Timer_TIFS, nhw_RADIO_fake_task_TRXEN_TIFS, and maybe_prepare_TIFS()
128 * This TIFS machine piggybacks on the main machine and its timer.
129 *
130 * And apart from this, there is an "abort" state machine, which is used to handle SW or another peripheral
131 * triggering a TASK which requires us to stop a transaction with the Phy midway.
132 * 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
133 * will want to stop it midway. So we tell the Phy when we start, when we expect to end, but also, when we
134 * want the Phy to recheck with us if the transaction needs to be aborted midway.
135 * This recheck time is set to the time anything may decide to stop. Which for simplicity is whenever *anything* may run.
136 * That is, whenever any timer is scheduled. As this includes other peripherals which may trigger tasks thru the PPI,
137 * or SW doing so after an interrupt.
138 * If at any point, a TASK that stops a transaction comes while that transaction is ongoing, the abort state machine will flag it,
139 * and the next time we need to respond to the Phy we will tell that we are stopping.
140 *
141 * Apart from these, there is the interaction with the Phy (check ext_2G4_libPhyComv1/docs):
142 * There is 3 different procedures for this (Tx, Rx & CCA) which fundamentally work in the same way.
143 * At start_Rx/Tx/CCA_ED() (which is called at the micros when the actual Tx/Rx/CCA/ED measurement starts),
144 * the Phy is told we want to start, and immediately we block until we get a response from the Phy.
145 * (1) Here the response may be that:
146 * * The Phy finished the procedure, in which case we just pre-program the main state machine timer,
147 * and set registers and other state accordingly. (as we are done interacting with the Phy for this operation)
148 * OR
149 * * The Phy asks us to reevaluate if we want to abort. In this case, we hold responding to the Phy
150 * and instead set the Timer_RADIO_abort_reeval to the time in which we need to respond to the Phy
151 * and let time pass until that microsecond is ended.
152 * At that point in time:
153 * * If SW (or whatever else may trigger a TASK) has caused the procedure to end, we tell the Phy
154 * we are aborting right now
155 * * If nothing stopped it yet, we respond with a new abort reevaluation time in the future to the Phy,
156 * and continue from (1).
157 * The idea is that Timer_RADIO_abort_reeval is a separate timer that runs in parallel to the main Timer_RADIO and any other
158 * 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
159 * anything else has affected the RADIO state in a way that requires us to stop the interaction with the Phy or not.
160 * 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
161 * as to raise or not the CCABUSY/IDLE signals.
162 * 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
163 * notification when the address has been received. At this point (address end) we pre-check some of the packet content (address for BLE adv,
164 * length, etc) and already set some status registers and make some decisions about if we should proceed with the packet or not.
165 *
166 * The CCA and ED procedures are so similar that they are handled with the same CCA_ED state in the main state machine,
167 * most of the same CCA_ED code, and the same CCA procedure to the Phy.
168 *
169 * For BLE Coded Phy, transmissions and receptions are actually handled as 2 piggybacking ones:
170 * One for the FEC1 block and another for the FEC2.
171 * * In transmission, during start_Tx() both FEC1 and FEC2 tx_req and tx_req_fec1 structures are
172 * filled in, and the transmission for the FEC1 is started. When the FEC2 transmission start time
173 * has been reached (the micros after the FEC1 has ended), the main state state machine will call
174 * start_Tx_FEC2() which will update the FEC2 tx_req, and start it. From there it will continue
175 * like a normal transmission until the CRC end.
176 * * In receptions similarly start_Rx() will prefill both rx_req structures. But: the 2nd rx_req
177 * will be updated after the FEC1 CI is received at start_Rx_FEC2(), and when the FEC1 ends.
178 * Unlike a Tx, a reception can take several code paths depending on the possibility of sync'ing,
179 * having an erroneous FEC1 or FEC2 packet. See docs/Rx_Phy_paths.svg for more info.
180 *
181 * The main state machine has a few conditions to transition differently for Coded Phy and normal
182 * packets.
183 */
184
185 #include <string.h>
186 #include <stdbool.h>
187 #include <stdint.h>
188 #include "bs_types.h"
189 #include "bs_tracing.h"
190 #include "bs_utils.h"
191 #include "bs_pc_2G4.h"
192 #include "bs_pc_2G4_utils.h"
193 #include "bs_rand.h"
194 #include "NHW_common_types.h"
195 #include "NHW_config.h"
196 #include "NHW_peri_types.h"
197 #include "NHW_RADIO.h"
198 #include "NHW_RADIO_signals.h"
199 #include "NHW_RADIO_utils.h"
200 #include "NHW_RADIO_timings.h"
201 #include "NHW_RADIO_bitcounter.h"
202 #include "NHW_RADIO_priv.h"
203 #include "nsi_hw_scheduler.h"
204 #include "NHW_AES_CCM.h"
205 #include "irq_ctrl.h"
206 #include "NRF_HWLowL.h"
207 #include "crc.h"
208 #include "nsi_tasks.h"
209 #include "nsi_hws_models_if.h"
210 #include "weak_stubs.h"
211
212 #if NHW_RADIO_TOTAL_INST > 1
213 #error "This model only supports 1 instance so far"
214 #endif
215
216 NRF_RADIO_Type NRF_RADIO_regs;
217
218 static bs_time_t Timer_RADIO = TIME_NEVER; //main radio timer
219 static 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)
220
221 static TIFS_state_t TIFS_state = TIFS_DISABLE;
222 static bool TIFS_ToTxNotRx = false; //Are we in a TIFS automatically starting a Tx from a Rx (true), or Rx from Tx (false)
223 static bs_time_t Timer_TIFS = TIME_NEVER;
224 static bool from_hw_tifs = false; /* Unfortunate hack due to the SW racing the HW to clear SHORTS*/
225
226 static RADIO_Rx_status_t rx_status;
227 static RADIO_Tx_status_t tx_status;
228 static RADIO_CCA_status_t cca_status;
229
230 static double bits_per_us; //Bits per us for the ongoing Tx or Rx
231
232 static bs_time_t next_recheck_time; // when we asked the phy to recheck (in our own time) next time
233 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)
234 static int aborting_set = 0; //If set, we will abort the current Tx/Rx/CCA at the next abort reevaluation
235
236 static nrfra_state_t radio_state;
237 static nrfra_sub_state_t radio_sub_state;
238
239 static uint8_t tx_buf[_NRF_MAX_PACKET_SIZE]; //starting from the header, and including CRC
240 static uint8_t rx_buf[_NRF_MAX_PACKET_SIZE]; // "
241 static uint8_t *rx_pkt_buffer_ptr = (uint8_t*)&rx_buf;
242
243 #if !NHW_RADIO_IS_54
244 static bool radio_POWER = false;
245 #endif
246
247 static double cheat_rx_power_offset;
248
249 static void start_Tx(void);
250 static void start_Tx_FEC2(void);
251 static void start_Rx(void);
252 static void start_Rx_FEC2(void);
253 static void start_CCA_ED(bool CCA_not_ED);
254 static void Rx_Addr_received(void);
255 static void Tx_abort_eval_respond(void);
256 static void Rx_abort_eval_respond(void);
257 #if 0 //Note6.b
258 static p2G4_rssi_power_t Rx_abort_imm_RSSI(void);
259 #endif
260 static void CCA_abort_eval_respond(void);
261 static void nhw_radio_device_address_match(uint8_t rx_buf[]);
262
radio_set_registers_defaults(void)263 static void radio_set_registers_defaults(void) {
264 //Registers' reset values:
265 NRF_RADIO_regs.FREQUENCY = 0x00000002;
266 NRF_RADIO_regs.SFD = 0xA7;
267 NRF_RADIO_regs.CCACTRL = 0x052D0000;
268 NRF_RADIO_regs.CTEINLINECONF = 0x00002800;
269 NRF_RADIO_regs.DFECTRL1 = 0x00023282;
270 for (int i = 0; i < 8; i++)
271 NRF_RADIO_regs.PSEL.DFEGPIO[i] = 0xFFFFFFFF;
272 NRF_RADIO_regs.DFEPACKET.MAXCNT = 0x00001000;
273
274 #if defined(NRF54L15) && !defined(RADIO_DATAWHITEIV_DATAWHITEIV_Msk)
275 NRF_RADIO_regs.DATAWHITE = 0x00890040;
276 #else
277 NRF_RADIO_regs.DATAWHITEIV = 0x00000040;
278 #endif
279
280 #if !NHW_RADIO_IS_54
281 NRF_RADIO_regs.MODECNF0 = 0x00000200;
282 NRF_RADIO_regs.POWER = 1;
283 #else
284 NRF_RADIO_regs.EDCTRL = 0x20000000;
285 NRF_RADIO_regs.TXPOWER = 0x00000013;
286 #endif
287 }
288
radio_reset(void)289 static void radio_reset(void) {
290 memset(&NRF_RADIO_regs, 0, sizeof(NRF_RADIO_regs));
291 radio_state = RAD_DISABLED;
292 radio_sub_state = SUB_STATE_INVALID;
293 Timer_RADIO = TIME_NEVER;
294
295 TIFS_state = TIFS_DISABLE;
296 TIFS_ToTxNotRx = false;
297 Timer_TIFS = TIME_NEVER;
298
299 radio_set_registers_defaults();
300
301 nhwra_signalif_reset();
302 }
303
nhw_radio_init(void)304 static void nhw_radio_init(void) {
305 nrfra_timings_init();
306 radio_reset();
307 #if !NHW_RADIO_IS_54
308 radio_POWER = false;
309 #endif
310 bits_per_us = 1;
311 }
312
313 NSI_TASK(nhw_radio_init, HW_INIT, 100);
314
nhw_radio_get_bpus(void)315 double nhw_radio_get_bpus(void) {
316 return bits_per_us;
317 }
318
nhwra_set_Timer_RADIO(bs_time_t t)319 static inline void nhwra_set_Timer_RADIO(bs_time_t t){
320 Timer_RADIO = t;
321 nsi_hws_find_next_event();
322 }
323
nhwra_set_Timer_abort_reeval(bs_time_t t)324 static inline void nhwra_set_Timer_abort_reeval(bs_time_t t){
325 Timer_RADIO_abort_reeval = t;
326 nsi_hws_find_next_event();
327 }
328
nhw_RADIO_TASK_TXEN(void)329 void nhw_RADIO_TASK_TXEN(void) {
330 if ( ( radio_state != RAD_DISABLED )
331 && ( radio_state != RAD_TXIDLE )
332 && ( radio_state != RAD_RXIDLE ) ){
333 bs_trace_warning_line_time(
334 "NRF_RADIO: TXEN received when the radio was not DISABLED or TX/RXIDLE but in state %i. It will be ignored. Expect problems\n",
335 radio_state);
336 return;
337 }
338 radio_state = RAD_TXRU;
339 NRF_RADIO_regs.STATE = RAD_TXRU;
340
341 nhwra_set_Timer_RADIO(nsi_hws_get_time() + nhwra_timings_get_rampup_time(1, from_hw_tifs));
342 }
343
nhw_RADIO_TASK_RXEN(void)344 void nhw_RADIO_TASK_RXEN(void) {
345 if ( ( radio_state != RAD_DISABLED )
346 && ( radio_state != RAD_TXIDLE )
347 && ( radio_state != RAD_RXIDLE ) ){
348 bs_trace_warning_line_time(
349 "NRF_RADIO: RXEN received when the radio was not DISABLED or TX/RXIDLE but in state %i. It will be ignored. Expect problems\n",
350 radio_state);
351 return;
352 }
353 TIFS_state = TIFS_DISABLE;
354 radio_state = RAD_RXRU;
355 NRF_RADIO_regs.STATE = RAD_RXRU;
356 nhwra_set_Timer_RADIO(nsi_hws_get_time() + nhwra_timings_get_rampup_time(0, from_hw_tifs));
357 }
358
abort_if_needed(void)359 static void abort_if_needed(void) {
360 if ( ( abort_fsm_state == Tx_Abort_reeval )
361 || ( abort_fsm_state == Rx_Abort_reeval )
362 || ( abort_fsm_state == CCA_Abort_reeval ) ){
363 //If the phy is waiting for a response from us, we need to tell it, that we are aborting whatever it was doing
364 aborting_set = 1;
365 }
366 /* Note: In Rx, we may be
367 * waiting to respond to the Phy to an abort reevaluation request abort_fsm_state == Rx_Abort_reeval
368 * or waiting to reach the address end time to respond to the Phy if we accepted the packet or not
369 * but not both
370 */
371 if ( radio_sub_state == RX_WAIT_FOR_ADDRESS_END ){
372 //we answer immediately to the phy rejecting the packet
373 p2G4_dev_rxv2_cont_after_addr_nc_b(false, NULL);
374 radio_sub_state = SUB_STATE_INVALID;
375 }
376 }
377
nhw_RADIO_TASK_START(void)378 void nhw_RADIO_TASK_START(void) {
379 if ( radio_state == RAD_TXIDLE ) {
380 bs_time_t Tx_start_time = nsi_hws_get_time() + nhwra_timings_get_TX_chain_delay();
381 radio_state = RAD_TXSTARTING;
382 NRF_RADIO_regs.STATE = RAD_TX;
383 nhwra_set_Timer_RADIO(Tx_start_time);
384 } else if ( radio_state == RAD_RXIDLE ) {
385 start_Rx();
386 } else {
387 bs_trace_warning_line_time(
388 "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",
389 radio_state);
390 }
391 }
392
nhw_RADIO_TASK_SOFTRESET(void)393 void nhw_RADIO_TASK_SOFTRESET(void) {
394 if (radio_state != RAD_DISABLED) {
395 bs_trace_warning_line_time(
396 "NRF_RADIO: TASK_SOFTRESET should only be used in disabled state."
397 "Current state %i\n", radio_state);
398 }
399
400 #if defined(RADIO_TASKS_SOFTRESET_TASKS_SOFTRESET_Msk)
401 //Reset all registers after interrupts (first is MODE), but not the PACKETPTR.
402 //Note: DFE PACKETPTR should also not be reset(?), but is not yet implemented
403 memset((void *)&NRF_RADIO_regs.MODE, 0, offsetof(NRF_RADIO_Type, PACKETPTR) - offsetof(NRF_RADIO_Type, MODE));
404 memset((void *)&NRF_RADIO_regs.CSTONES, 0, sizeof(NRF_RADIO_Type) - offsetof(NRF_RADIO_Type, CSTONES));
405 radio_set_registers_defaults();
406 #endif
407 }
408
nhw_RADIO_TASK_CCASTART(void)409 void nhw_RADIO_TASK_CCASTART(void) {
410 if ((radio_state != RAD_RXIDLE)){
411 bs_trace_warning_line_time(
412 "NRF_RADIO: CCASTART received when the radio was not RXIDLE but in state %i. "
413 "It will be ignored. Expect problems\n",
414 radio_state);
415 return;
416 }
417 start_CCA_ED(1);
418 }
419
nhw_RADIO_TASK_CCASTOP(void)420 void nhw_RADIO_TASK_CCASTOP(void) {
421 if (( radio_state == RAD_CCA_ED ) && ( cca_status.CCA_notED )) {
422 abort_if_needed();
423 radio_state = RAD_RXIDLE;
424 NRF_RADIO_regs.STATE = RAD_RXIDLE;
425 nhwra_set_Timer_RADIO(TIME_NEVER);
426 nhw_RADIO_signal_EVENTS_CCASTOPPED(0);
427 } else {
428 bs_trace_info_line_time(3,
429 "NRF_RADIO: TASK_CCASTOP received while the radio was not on a CCA procedure (was %i, %i). "
430 "It will be ignored\n",
431 radio_state, cca_status.CCA_notED);
432 }
433 }
434
nhw_RADIO_TASK_EDSTART(void)435 void nhw_RADIO_TASK_EDSTART(void) {
436 if ((radio_state != RAD_RXIDLE)){
437 bs_trace_warning_line_time(
438 "NRF_RADIO: EDSTART received when the radio was not RXIDLE but in state %i. "
439 "It will be ignored. Expect problems\n",
440 radio_state);
441 return;
442 }
443 start_CCA_ED(0);
444 }
445
nhw_RADIO_TASK_EDSTOP(void)446 void nhw_RADIO_TASK_EDSTOP(void) {
447 if (( radio_state == RAD_CCA_ED ) && ( cca_status.CCA_notED == 0)) {
448 abort_if_needed();
449 radio_state = RAD_RXIDLE;
450 NRF_RADIO_regs.STATE = RAD_RXIDLE;
451 nhwra_set_Timer_RADIO(TIME_NEVER);
452 nhw_RADIO_signal_EVENTS_EDSTOPPED(0);
453 } else {
454 bs_trace_info_line_time(3,
455 "NRF_RADIO: TASK_EDSTOP received while the radio was not on a ED procedure (was %i, %i). "
456 "It will be ignored\n",
457 radio_state, cca_status.CCA_notED);
458 }
459 }
460
nhw_RADIO_TASK_STOP(void)461 void nhw_RADIO_TASK_STOP(void) {
462 nhw_radio_stop_bit_counter();
463
464 if ((radio_state == RAD_TX) || (radio_state == RAD_TXSTARTING)) {
465 if (radio_state == RAD_TX) {
466 abort_if_needed();
467 }
468 radio_state = RAD_TXIDLE;
469 NRF_RADIO_regs.STATE = RAD_TXIDLE;
470 nhwra_set_Timer_RADIO(TIME_NEVER);
471 } else if ( radio_state == RAD_RX ){
472 abort_if_needed();
473 radio_state = RAD_RXIDLE;
474 NRF_RADIO_regs.STATE = RAD_RXIDLE;
475 nhwra_set_Timer_RADIO(TIME_NEVER);
476 } else if ( radio_state == RAD_CCA_ED ){
477 //The documentation is not clear about what happens if we get a STOP during a CCA or ED procedure,
478 //but it seems for CCA it can cause a bit of a mess depending on CCA mode.
479 //the behavior here is that we stop just like if it was an active Rx, and do *not* trigger a CCASTOPPED or EDSTOPPED event
480 bs_trace_warning_line_time(
481 "NRF_RADIO: TASK_STOP received while the radio was performing a CCA or ED procedure. "
482 "In this models we stop the procedure, but this can cause a mess in real HW\n");
483 abort_if_needed();
484 radio_state = RAD_RXIDLE;
485 NRF_RADIO_regs.STATE = RAD_RXIDLE;
486 nhwra_set_Timer_RADIO(TIME_NEVER);
487 } else {
488 bs_trace_warning_line_time(
489 "NRF_RADIO: TASK_STOP received while the radio was not on either TX or RX but in state %i. "
490 "It will be ignored\n",
491 radio_state);
492 }
493 }
494
nhw_RADIO_TASK_DISABLE(void)495 void nhw_RADIO_TASK_DISABLE(void) {
496 nhw_radio_stop_bit_counter();
497
498 if ((radio_state == RAD_TX) || (radio_state == RAD_TXSTARTING)) {
499 if (radio_state == RAD_TX) {
500 abort_if_needed();
501 }
502 radio_state = RAD_TXIDLE; //Momentary (will be changed in the if below)
503 NRF_RADIO_regs.STATE = RAD_TXIDLE;
504 } else if ( radio_state == RAD_RX ){
505 abort_if_needed();
506 radio_state = RAD_RXIDLE; //Momentary (will be changed in the if below)
507 NRF_RADIO_regs.STATE = RAD_RXIDLE;
508 } else if ( radio_state == RAD_CCA_ED ){
509 //The documentation is not clear about what happens if we get a disable during a CCA or ED procedure,
510 //the assumption here is that we stop just like if it was an active Rx, but do not trigger a CCASTOPPED or EDSTOPPED event
511 abort_if_needed();
512 radio_state = RAD_RXIDLE; //Momentary (will be changed in the if below)
513 NRF_RADIO_regs.STATE = RAD_RXIDLE;
514 }
515
516 if (TIFS_state != TIFS_DISABLE) {
517 TIFS_state = TIFS_DISABLE;
518 nhwra_set_Timer_RADIO(TIME_NEVER);
519 Timer_TIFS = TIME_NEVER;
520 }
521
522 if ( ( radio_state == RAD_TXRU ) || ( radio_state == RAD_TXIDLE ) ) {
523 radio_state = RAD_TXDISABLE;
524 NRF_RADIO_regs.STATE = RAD_TXDISABLE;
525 TIFS_state = TIFS_DISABLE;
526 nhwra_set_Timer_RADIO(nsi_hws_get_time() + nhwra_timings_get_TX_rampdown_time());
527 } else if ( ( radio_state == RAD_RXRU ) || ( radio_state == RAD_RXIDLE ) ) {
528 radio_state = RAD_RXDISABLE;
529 NRF_RADIO_regs.STATE = RAD_RXDISABLE;
530 TIFS_state = TIFS_DISABLE;
531 nhwra_set_Timer_RADIO(nsi_hws_get_time() + nhwra_timings_get_RX_rampdown_time());
532 } else if ( radio_state == RAD_DISABLED ) {
533 //It seems the radio will also signal a DISABLED event even if it was already disabled
534 nhw_radio_stop_bit_counter();
535 nhw_RADIO_signal_EVENTS_DISABLED(0);
536 }
537 }
538
nhw_RADIO_TASK_RSSISTART(void)539 void nhw_RADIO_TASK_RSSISTART(void) {
540 if ((radio_state != RAD_RX) && (radio_state != RAD_RXIDLE)) {
541 bs_trace_warning_time_line("TASK_RSSISTART received while the radio was not in Rx. "
542 "The spec does not allow this. We just use the last Rx value in the model\n");
543 }
544
545 // When we receive this, wrt. the Phy communication either:
546 // a) we have not started anything (radio_state != RAD_RX) (phy time is in the past in the previous transaction end)
547 // b) Phy is waiting during an abort reevaluation before address match
548 // c) we have got the addr and the phy is waiting for a response to it (normal case, where the stack triggers RSSISTART via ADDRESS short)
549 // d) the phy is waiting for us, in the middle or an abort reevaluation after addr.
550 // d.1) because stack triggered RSSISTART in SW after ADDRESS (time == phy time == address end time)
551 // d.2) because stack triggered RSSISTART in SW anywhere later in packet reception (time == phy time)
552 // e) or we have finished a Phy Rx all together but the RADIO is still in Rx (we already got the CRC end from the Phy but we are still processing the packet in the RADIO, due to Rx prop. delay)
553 //
554 // Best approach:
555 // if a)
556 // if real RADIO reports an old measured value then best is to use our latest
557 // otherwise to do a plain RSSI measurement now
558 // Note: It seems it is possible to do a RSSI measurement after ramp-up with the RADIO in RXIDLE. So we'd want to do a normal RSSI measurement in this case. But then we'd need to distinguish it from c) and e)
559 // if b) => do an immediate RSSI measurement during abort reeval (this case we don't yet handle well now)
560 // if c) best is to use the RSSI measurement from the addr => last Rx measurement
561 // if d.1) => same as c)
562 // if d.2) best to do is an immediate RSSI measurement during abort, but last rx measurement is going to be almost the same
563 // For d.1) an immediate RSSI measurement would produce the same result (just a bit of Phy comm overhead)
564 // if e) => use last Rx measurement
565
566 p2G4_rssi_power_t RSSI_value;
567 #if 0 //Note6.b
568 if (abort_fsm_state == Rx_Abort_reeval) {
569 //Respond with an immediate RSSI request during abort, get that response and let nhw_radio_timer_abort_reeval_triggered() handle it further
570 RSSI_value = Rx_abort_imm_RSSI();
571 } else
572 #endif
573 {
574 RSSI_value = rx_status.rx_resp.rssi.RSSI;
575 }
576
577 /* See Note6 */
578 NRF_RADIO_regs.RSSISAMPLE = nhwra_RSSI_value_to_modem_format(
579 p2G4_RSSI_value_to_dBm(RSSI_value)
580 + cheat_rx_power_offset
581 );
582 #if !NHW_RADIO_IS_54
583 nhw_RADIO_signal_EVENTS_RSSIEND(0);
584 #endif
585 }
586
nhw_RADIO_TASK_RSSISTOP(void)587 void nhw_RADIO_TASK_RSSISTOP(void) {
588 /* Nothing to be done */
589 }
590
591 #if !NHW_RADIO_IS_54
nhw_RADIO_regw_sideeffects_POWER(void)592 void nhw_RADIO_regw_sideeffects_POWER(void) {
593 if ( NRF_RADIO_regs.POWER == 0 ){
594 radio_POWER = false;
595 } else {
596 if ( radio_POWER == false ){
597 radio_POWER = true;
598 abort_if_needed();
599 radio_reset();
600 nsi_hws_find_next_event();
601 }
602 }
603 }
604 #endif
605
606 /**
607 * This is a fake task meant to start a HW timer for the TX->RX or RX->TX TIFS
608 */
nhw_RADIO_fake_task_TRXEN_TIFS(void)609 void nhw_RADIO_fake_task_TRXEN_TIFS(void) {
610 if ( TIFS_state == TIFS_WAITING_FOR_DISABLE ) {
611 TIFS_state = TIFS_TRIGGERING_TRX_EN;
612 nhwra_set_Timer_RADIO(Timer_TIFS);
613 if ( Timer_RADIO < nsi_hws_get_time() ){
614 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");
615 }
616 }
617 }
618
619 /**
620 * If the HW automatic TIFS switch is enabled, prepare the internals for an automatic switch
621 * (when a fake_task_TRXEN_TIFS is automatically triggered after a disable due to a shortcut)
622 * otherwise do nothing
623 *
624 * Input Tx_Not_Rx: Are we finishing a Tx (true) or an Rx (false)
625 */
maybe_prepare_TIFS(bool Tx_Not_Rx)626 void maybe_prepare_TIFS(bool Tx_Not_Rx){
627 bs_time_t delta;
628 if ( !nhwra_is_HW_TIFS_enabled() ) {
629 TIFS_state = TIFS_DISABLE;
630 return;
631 }
632 if ( NRF_RADIO_regs.SHORTS & RADIO_SHORTS_DISABLED_TXEN_Msk ){
633 TIFS_ToTxNotRx = true;
634 } else {
635 TIFS_ToTxNotRx = false;
636 }
637
638 if ( Tx_Not_Rx ){ //End of Tx
639 delta = NRF_RADIO_regs.TIFS + nhwra_timings_get_TX_chain_delay() - nhwra_timings_get_rampup_time(0, 1) - 3; /*open slightly earlier to have jitter margin*/
640 } else { //End of Rx
641 delta = NRF_RADIO_regs.TIFS - nhwra_timings_get_Rx_chain_delay() - nhwra_timings_get_TX_chain_delay() - nhwra_timings_get_rampup_time(1, 1) + 1;
642 }
643 Timer_TIFS = nsi_hws_get_time() + delta;
644 TIFS_state = TIFS_WAITING_FOR_DISABLE; /* In Timer_TIFS we will trigger a TxEN or RxEN */
645 }
646
maybe_signal_event_RATEBOOST(void)647 static void maybe_signal_event_RATEBOOST(void) {
648 if (rx_status.CI == 1) {
649 nhw_RADIO_signal_EVENTS_RATEBOOST(0);
650 }
651 }
652
653 /**
654 * The main radio timer (Timer_RADIO) has just triggered,
655 * continue whatever activity we are on
656 * (typically do something at the end/start of a state, set the new state
657 * and schedule further the next state change)
658 */
nhw_radio_timer_triggered(void)659 static void nhw_radio_timer_triggered(void) {
660 if ( radio_state == RAD_TXRU ){
661 radio_state = RAD_TXIDLE;
662 NRF_RADIO_regs.STATE = RAD_TXIDLE;
663 nhwra_set_Timer_RADIO(TIME_NEVER);
664 nhw_RADIO_signal_EVENTS_READY(0);
665 nhw_RADIO_signal_EVENTS_TXREADY(0);
666 } else if ( radio_state == RAD_RXRU ){
667 radio_state = RAD_RXIDLE;
668 NRF_RADIO_regs.STATE = RAD_RXIDLE;
669 nhwra_set_Timer_RADIO(TIME_NEVER);
670 nhw_RADIO_signal_EVENTS_READY(0);
671 nhw_RADIO_signal_EVENTS_RXREADY(0);
672 } else if ( radio_state == RAD_TXSTARTING ){
673 nhwra_set_Timer_RADIO(TIME_NEVER);
674 start_Tx();
675 } else if ( radio_state == RAD_TX ){
676 if ( radio_sub_state == TX_WAIT_FOR_ADDRESS_END ){
677 if (tx_status.codedphy) {
678 radio_sub_state = TX_WAIT_FOR_FEC1_END;
679 nhwra_set_Timer_RADIO(tx_status.FEC2_start_time);
680 } else {
681 radio_sub_state = TX_WAIT_FOR_PAYLOAD_END;
682 nhwra_set_Timer_RADIO(tx_status.PAYLOAD_end_time);
683 }
684 nhw_RADIO_signal_EVENTS_ADDRESS(0);
685 nhw_RADIO_signal_EVENTS_FRAMESTART(0); //See note on FRAMESTART
686 } else if ( radio_sub_state == TX_WAIT_FOR_FEC1_END ) {
687 start_Tx_FEC2();
688 radio_sub_state = TX_WAIT_FOR_PAYLOAD_END;
689 nhwra_set_Timer_RADIO(tx_status.PAYLOAD_end_time);
690 } else if ( radio_sub_state == TX_WAIT_FOR_PAYLOAD_END ) {
691 radio_sub_state = TX_WAIT_FOR_CRC_END;
692 nhwra_set_Timer_RADIO(tx_status.CRC_end_time);
693 nhw_RADIO_signal_EVENTS_PAYLOAD(0);
694 } else if ( radio_sub_state == TX_WAIT_FOR_CRC_END ) {
695 radio_sub_state = SUB_STATE_INVALID;
696 radio_state = RAD_TXIDLE;
697 NRF_RADIO_regs.STATE = RAD_TXIDLE;
698 nhwra_set_Timer_RADIO(TIME_NEVER);
699 nhw_radio_stop_bit_counter();
700 nhw_RADIO_signal_EVENTS_END(0);
701 nhw_RADIO_signal_EVENTS_PHYEND(0); //See note on EVENTS_PHYEND
702 maybe_prepare_TIFS(true);
703 } else { //SUB_STATE_INVALID
704 bs_trace_error_time_line("programming error\n");
705 }
706 } else if ( radio_state == RAD_RX ){
707 if ( radio_sub_state == RX_WAIT_FOR_ADDRESS_END ) {
708 nhw_RADIO_signal_EVENTS_SYNC(0); //See note on EVENTS_SYNC
709 nhw_RADIO_signal_EVENTS_ADDRESS(0);
710 nhw_RADIO_signal_EVENTS_FRAMESTART(0); //See note on FRAMESTART
711 nhwra_set_Timer_RADIO(TIME_NEVER); //Provisionally clear the RADIO timer for the Rx cont.
712 Rx_Addr_received();
713 if (rx_status.codedphy) {
714 radio_sub_state = RX_WAIT_FOR_FEC1_END;
715 // The timer will be set once we get the Phy FEC1 end response
716 } else {
717 radio_sub_state = RX_WAIT_FOR_PAYLOAD_END;
718 nhwra_set_Timer_RADIO(rx_status.PAYLOAD_End_Time);
719 }
720 } else if ( radio_sub_state == RX_WAIT_FOR_FEC1_END ) {
721 maybe_signal_event_RATEBOOST();
722 /* The next state transition will be programmed when we get the Phy response for the FEC2 */
723 nhwra_set_Timer_RADIO(TIME_NEVER);
724 start_Rx_FEC2();
725 } else if ( radio_sub_state == RX_WAIT_FOR_PAYLOAD_END ) {
726 radio_sub_state = RX_WAIT_FOR_CRC_END;
727 nhwra_set_Timer_RADIO(rx_status.CRC_End_Time);
728 nhw_RADIO_signal_EVENTS_PAYLOAD(0);
729 } else if ( radio_sub_state == RX_WAIT_FOR_CRC_END ) {
730 #if !NHW_RADIO_IS_54
731 //The 54 CCM is triggered through the DPPI like in reality
732 nhw_ccm_radio_received_packet(!rx_status.CRC_OK);
733 #endif
734 radio_sub_state = SUB_STATE_INVALID;
735 radio_state = RAD_RXIDLE;
736 NRF_RADIO_regs.STATE = RAD_RXIDLE;
737 nhwra_set_Timer_RADIO(TIME_NEVER);
738 if ( rx_status.CRC_OK ) {
739 nhw_RADIO_signal_EVENTS_CRCOK(0);
740 } else {
741 nhw_RADIO_signal_EVENTS_CRCERROR(0);
742 }
743 nhw_radio_stop_bit_counter();
744 nhw_RADIO_signal_EVENTS_PHYEND(0); //See note on EVENTS_PHYEND
745 nhw_RADIO_signal_EVENTS_END(0);
746 maybe_prepare_TIFS(false);
747 } else { //SUB_STATE_INVALID
748 bs_trace_error_time_line("programming error\n");
749 }
750 } else if ( radio_state == RAD_CCA_ED ){
751 radio_state = RAD_RXIDLE;
752 NRF_RADIO_regs.STATE = RAD_RXIDLE;
753 nhwra_set_Timer_RADIO(TIME_NEVER);
754 if (cca_status.CCA_notED) { //CCA procedure ended
755 if (cca_status.is_busy) {
756 nhw_RADIO_signal_EVENTS_CCABUSY(0);
757 } else {
758 nhw_RADIO_signal_EVENTS_CCAIDLE(0);
759 }
760 } else { //ED procedure ended
761 nhw_RADIO_signal_EVENTS_EDEND(0);
762 }
763 } else if ( radio_state == RAD_TXDISABLE ){
764 radio_state = RAD_DISABLED;
765 NRF_RADIO_regs.STATE = RAD_DISABLED;
766 nhwra_set_Timer_RADIO(TIME_NEVER);
767 nhw_radio_stop_bit_counter();
768 nhw_RADIO_signal_EVENTS_DISABLED(0);
769 } else if ( radio_state == RAD_RXDISABLE ){
770 radio_state = RAD_DISABLED;
771 NRF_RADIO_regs.STATE = RAD_DISABLED;
772 nhwra_set_Timer_RADIO(TIME_NEVER);
773 nhw_radio_stop_bit_counter();
774 nhw_RADIO_signal_EVENTS_DISABLED(0);
775 } else {
776 if ( ( radio_state == RAD_DISABLED ) && ( TIFS_state == TIFS_TRIGGERING_TRX_EN ) ) {
777 if ( Timer_RADIO != Timer_TIFS ){
778 bs_trace_warning_line_time("NRF_RADIO: TIFS Ups 3\n");
779 }
780 TIFS_state = TIFS_DISABLE;
781 nhwra_set_Timer_RADIO(TIME_NEVER);
782 from_hw_tifs = true;
783 if ( TIFS_ToTxNotRx ) {
784 nhw_RADIO_TASK_TXEN();
785 } else {
786 nhw_RADIO_TASK_RXEN();
787 }
788 from_hw_tifs = false;
789 } else {
790 bs_trace_error_line_time(
791 "NRF_RADIO: this should not have happened (radio_state =%i)\n",
792 radio_state);
793 }
794 }
795 }
796
797 NSI_HW_EVENT(Timer_RADIO, nhw_radio_timer_triggered, 990 /*We want the radio to be one of the very last to avoid unnecessary abort re-evaluations to the Phy*/);
798
799 /**
800 * The abort reevaluation timer has just triggered,
801 * => we can now respond to the Phy with our abort decision
802 */
nhw_radio_timer_abort_reeval_triggered(void)803 static void nhw_radio_timer_abort_reeval_triggered(void) {
804 nhwra_set_Timer_abort_reeval(TIME_NEVER);
805
806 if ( abort_fsm_state == Tx_Abort_reeval ){
807 abort_fsm_state = No_pending_abort_reeval;
808 Tx_abort_eval_respond();
809 } else if ( abort_fsm_state == Rx_Abort_reeval ) {
810 abort_fsm_state = No_pending_abort_reeval;
811 Rx_abort_eval_respond();
812 } else if ( abort_fsm_state == CCA_Abort_reeval ) {
813 abort_fsm_state = No_pending_abort_reeval;
814 CCA_abort_eval_respond();
815 } else {
816 bs_trace_error_line("The abort timer was left running.. somebody forgot to cleanup..\n");
817 }
818 }
819
820 NSI_HW_EVENT(Timer_RADIO_abort_reeval, nhw_radio_timer_abort_reeval_triggered, 999 /* Purposely the last (all other events must have been evaluated before) */);
821
822 /**
823 * Handle all possible responses to a Tx request from the Phy
824 */
handle_Tx_response(int ret)825 static void handle_Tx_response(int ret){
826 if (ret == -1){
827 bs_trace_raw_manual_time(3, nsi_hws_get_time(),"The phy disconnected us during a Tx\n");
828 hwll_disconnect_phy_and_exit();
829 } else if (ret == P2G4_MSG_TX_END) {
830 bs_time_t end_time = hwll_dev_time_from_phy(tx_status.tx_resp.end_time);
831 phy_sync_ctrl_set_last_phy_sync_time(end_time);
832 //The main machine was already pre-programmed at the Tx Start, no need to do anything else now
833 } else if ( ret == P2G4_MSG_ABORTREEVAL ) {
834 phy_sync_ctrl_set_last_phy_sync_time( next_recheck_time );
835 abort_fsm_state = Tx_Abort_reeval;
836 nhwra_set_Timer_abort_reeval(next_recheck_time);
837 }
838 }
839
840 /**
841 * Set the Phy abort structure to the next time we will want to either abort or have a recheck
842 * And store in next_recheck_time the next recheck time
843 */
update_abort_struct(p2G4_abort_t * abort,bs_time_t * next_recheck_time)844 static void update_abort_struct(p2G4_abort_t *abort, bs_time_t *next_recheck_time){
845 //We will want to recheck next time anything may decide to stop the radio, that can be SW or HW
846 //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
847 *next_recheck_time = nsi_hws_get_next_event_time();
848 abort->recheck_time = hwll_phy_time_from_dev(*next_recheck_time);
849
850 //We either have decided already we want to abort so we do it right now
851 //or we have not decided yet
852 if ( aborting_set == 1 ) {
853 aborting_set = 0; //By returning nsi_hws_get_time(), we are aborting right now
854 abort->abort_time = hwll_phy_time_from_dev(nsi_hws_get_time());
855 } else {
856 abort->abort_time = TIME_NEVER;
857 }
858 }
859
860 /**
861 * We have reached the time in which we wanted to reevaluate if we would abort or not
862 * so we answer to the Phy with our decision
863 */
Tx_abort_eval_respond(void)864 static void Tx_abort_eval_respond(void) {
865 //The abort must have been evaluated by now so we can respond to the waiting phy
866 p2G4_abort_t *abort = &tx_status.tx_req.abort;
867
868 update_abort_struct(abort, &next_recheck_time);
869
870 int ret = p2G4_dev_provide_new_tx_abort_nc_b(abort);
871
872 handle_Tx_response(ret);
873 }
874
875 /*
876 * Actually start the Tx in this microsecond (+ the Tx chain delay in the Phy)
877 * (For coded phy, starts the FEC1 Tx itself, and prepares the FEC2 to be started later by start_Tx_FEC2() )
878 */
start_Tx(void)879 static void start_Tx(void) {
880
881 radio_state = RAD_TX;
882 NRF_RADIO_regs.STATE = RAD_TX;
883
884 nhwra_check_packet_conf();
885
886 //TOLOW: Add support for other packet formats and bitrates
887 uint8_t preamble_len = 0;
888 uint8_t address_len = 0;
889 uint8_t header_len = 0;
890 uint payload_len = 0;
891 uint8_t crc_len = nhwra_get_crc_length();
892 uint8_t CI = 0;
893 uint8_t main_packet_coding_rate = 0;
894
895 tx_status.codedphy = false;
896
897 if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_1Mbit) {
898 preamble_len = 1; //1 byte
899 address_len = 4;
900 header_len = 2;
901 bits_per_us = 1;
902 } else if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_2Mbit) {
903 preamble_len = 2; //2 bytes
904 address_len = 4;
905 header_len = 2;
906 bits_per_us = 2;
907 } else if ((NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_LR125Kbit)
908 || (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_LR500Kbit)) {
909 tx_status.codedphy = true;
910 address_len = 4;
911 header_len = 2;
912 if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_LR125Kbit) {
913 bits_per_us = 0.125;
914 CI = 0; //0b00
915 main_packet_coding_rate = 8;
916 } else { /* RADIO_MODE_MODE_Ble_LR500Kbit */
917 bits_per_us = 0.5;
918 CI = 1; //0b01
919 main_packet_coding_rate = 2;
920 }
921 } else if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ieee802154_250Kbit) {
922 preamble_len = 4;
923 address_len = 1;
924 header_len = 1;
925 bits_per_us = 0.25;
926 }
927
928 payload_len = nhwra_tx_copy_payload(tx_buf);
929
930 /* This code should be generalized to support any CRC configuration (CRCCNF, CRCINIT AND CRCPOLY)
931 * When doing so, we should still calculate the ble and 154 crc's with their optimized table implementations
932 * Here we just assume the CRC is configured as it should given the modulation */
933 uint32_t crc_init = NRF_RADIO_regs.CRCINIT & RADIO_CRCINIT_CRCINIT_Msk;
934 if (nhwra_is_ble_mode(NRF_RADIO_regs.MODE)) {
935 append_crc_ble(tx_buf, header_len + payload_len, crc_init);
936 } else if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ieee802154_250Kbit) {
937 //15.4 does not CRC the length (header) field
938 append_crc_154(&tx_buf[header_len], payload_len, crc_init);
939 }
940
941 uint main_packet_size; //Main "packet" size (the payload sent thru the phy)
942 bs_time_t packet_duration = 0; //Main packet duration (from preamble to CRC except for codedPhy which is just the FEC2)
943
944 if (!tx_status.codedphy) {
945 packet_duration = preamble_len*8 + address_len*8;
946 } else {
947 packet_duration = 3; //TERM2
948 }
949 packet_duration += header_len*8 + payload_len*8 + crc_len*8;
950 packet_duration /= bits_per_us;
951 main_packet_size = header_len + payload_len + crc_len;
952
953 bs_time_t payload_start_time;
954 bs_time_t main_packet_start_time;
955
956 if (tx_status.codedphy) {
957 tx_status.ADDRESS_end_time = nsi_hws_get_time() + (bs_time_t)(80 + 256 - nhwra_timings_get_TX_chain_delay());
958 payload_start_time = tx_status.ADDRESS_end_time + 16 + 24;/* CI = 16us; TERM1= 24us */
959
960 bs_time_t fec1_duration = 80 + 256 + 16 + 24;
961
962 nhwra_prep_tx_request(&tx_status.tx_req_fec1, 1, fec1_duration, hwll_phy_time_from_dev(nsi_hws_get_time()), 8);
963 update_abort_struct(&tx_status.tx_req_fec1.abort, &next_recheck_time);
964 main_packet_start_time = tx_status.tx_req_fec1.end_tx_time + 1;
965 tx_status.FEC2_start_time = main_packet_start_time; /* in air */
966 } else {
967 tx_status.ADDRESS_end_time = nsi_hws_get_time() + (bs_time_t)((preamble_len*8 + address_len*8)/bits_per_us) - nhwra_timings_get_TX_chain_delay();
968 payload_start_time = tx_status.ADDRESS_end_time;
969 main_packet_start_time = hwll_phy_time_from_dev(nsi_hws_get_time());
970 }
971 tx_status.PAYLOAD_end_time = payload_start_time + (bs_time_t)(8*(header_len + payload_len)/bits_per_us);
972 tx_status.CRC_end_time = tx_status.PAYLOAD_end_time + (bs_time_t)(crc_len*8/bits_per_us);
973
974 nhwra_prep_tx_request(&tx_status.tx_req, main_packet_size, packet_duration,
975 main_packet_start_time, main_packet_coding_rate);
976 update_abort_struct(&tx_status.tx_req.abort, &next_recheck_time);
977
978 int ret;
979 if (tx_status.codedphy) {
980 //Request the FEC1 Tx from the Phy:
981 ret = p2G4_dev_req_txv2_nc_b(&tx_status.tx_req_fec1, &CI, &tx_status.tx_resp);
982 } else { /* not codedphy */
983 //Request the Tx from the Phy:
984 ret = p2G4_dev_req_txv2_nc_b(&tx_status.tx_req, tx_buf, &tx_status.tx_resp);
985 }
986 handle_Tx_response(ret);
987
988 radio_sub_state = TX_WAIT_FOR_ADDRESS_END;
989 nhwra_set_Timer_RADIO(tx_status.ADDRESS_end_time);
990 }
991
start_Tx_FEC2(void)992 static void start_Tx_FEC2(void) {
993 int ret;
994 update_abort_struct(&tx_status.tx_req.abort, &next_recheck_time);
995 tx_status.tx_req.phy_address = 0; /* An invalid address */
996 ret = p2G4_dev_req_txv2_nc_b(&tx_status.tx_req, tx_buf, &tx_status.tx_resp);
997 handle_Tx_response(ret);
998 }
999
Rx_handle_CI_reception(void)1000 static void Rx_handle_CI_reception(void) {
1001 rx_status.CI = rx_buf[0] & 0x3;
1002
1003 if ((rx_status.rx_resp.packet_size < 1) || (rx_status.CI > 1)) {
1004 bs_trace_warning_time_line("%s: Received supposed BLE CodedPhy FEC1 without CI or corrupted CI (%i, %i)\n",
1005 __func__, rx_status.rx_resp.packet_size, rx_status.CI);
1006 }
1007
1008 NRF_RADIO_regs.PDUSTAT |= (rx_status.CI << RADIO_PDUSTAT_CISTAT_Pos) & RADIO_PDUSTAT_CISTAT_Msk;
1009
1010 if (rx_status.rx_resp.status != P2G4_RXSTATUS_OK) {
1011 /* Error during CI decoding, we don't know how many bits, and if it would have recovered.
1012 * So, we just do a 50% drop of having each CI bit corrupted or not */
1013 int error;
1014 error = bs_random_Bern(RAND_PROB_1/2);
1015 NRF_RADIO_regs.PDUSTAT ^= error << (RADIO_PDUSTAT_CISTAT_Pos + 1); /* The don't-care bit in CI */
1016
1017 error = bs_random_Bern(RAND_PROB_1/2);
1018 if (error) {
1019 NRF_RADIO_regs.PDUSTAT ^= 1 << (RADIO_PDUSTAT_CISTAT_Pos);
1020 rx_status.CI ^= 1;
1021 rx_status.CI_error = true;
1022 }
1023 }
1024 }
1025
Rx_handle_end_response(bs_time_t end_time)1026 static void Rx_handle_end_response(bs_time_t end_time) {
1027
1028 if (rx_status.inFEC1 == true) { /* End of CodedPhy packet FEC1 */
1029 Rx_handle_CI_reception();
1030
1031 } else { //Normal packet or end of FEC2
1032 if (rx_status.rx_resp.status != P2G4_RXSTATUS_HEADER_ERROR) {
1033 rx_status.CRC_End_Time = end_time + nhwra_timings_get_Rx_chain_delay();
1034 } //Otherwise we do not really now how the Nordic RADIO behaves depending on
1035 //where the biterrors are and so forth. So let's always behave like if the
1036 //packet lenght was received correctly, and just report a CRC error at the
1037 //end of the CRC
1038
1039 if ( rx_status.rx_resp.status == P2G4_RXSTATUS_OK ){
1040 NRF_RADIO_regs.RXCRC = nhwra_get_rx_crc_value(rx_buf, rx_status.rx_resp.packet_size);
1041 rx_status.CRC_OK = 1;
1042 NRF_RADIO_regs.CRCSTATUS = 1;
1043 }
1044 }
1045 }
1046
1047
Rx_handle_address_end_response(bs_time_t address_time)1048 static void Rx_handle_address_end_response(bs_time_t address_time) {
1049
1050 rx_status.ADDRESS_End_Time = address_time + nhwra_timings_get_Rx_chain_delay();
1051
1052 if ((rx_status.codedphy == true) && (rx_status.inFEC1)) {
1053 rx_status.FEC2_start_time = address_time + 16 + 24 + 1; /* It will be updated on the FEC1 Rx end */
1054 rx_status.packet_rejected = false; //We always accept the FEC1 part
1055
1056 //Let's set a very provisional packet end time, in case the Tx aborts between FEC1 and FEC2:
1057 rx_status.PAYLOAD_End_Time = rx_status.FEC2_start_time + 2*8/bits_per_us
1058 + nhwra_timings_get_Rx_chain_delay(); /* An empty packet */
1059 rx_status.CRC_End_Time = rx_status.PAYLOAD_End_Time + rx_status.CRC_duration;
1060 return;
1061 }
1062 //Otherwise, FEC2 or not Coded Phy
1063
1064 uint length = nhwra_get_payload_length(rx_buf);
1065 uint max_length = nhwra_get_MAXLEN();
1066
1067 if (length > max_length) {
1068 // We reject the packet right away, setting the CRC error, and timers as expected
1069 bs_trace_warning_time_line("NRF_RADIO: received a packet longer than the configured MAXLEN (%i>%i). Truncating it\n", length, max_length);
1070 length = max_length;
1071 NRF_RADIO_regs.PDUSTAT |= RADIO_PDUSTAT_PDUSTAT_Msk;
1072 rx_status.packet_rejected = true;
1073 } else {
1074 rx_status.packet_rejected = false;
1075 }
1076 if (rx_status.CI_error) {
1077 /* Let's just stop the Phy reception here, as continuing does not give us anything anymore */
1078 rx_status.packet_rejected = true;
1079 }
1080
1081 //TODO: Discard Ieee802154_250Kbit frames with length == 0
1082
1083 bs_time_t payload_end = 0;
1084
1085 if (nhwra_is_ble_mode(NRF_RADIO_regs.MODE)) {
1086 payload_end = rx_status.rx_resp.rx_time_stamp + (bs_time_t)((2+length)*8/bits_per_us);
1087 } else if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ieee802154_250Kbit) {
1088 payload_end = rx_status.rx_resp.rx_time_stamp + (bs_time_t)((1+length)*8/bits_per_us);
1089 } //Eventually this should be generalized with the packet configuration
1090
1091 rx_status.PAYLOAD_End_Time = nhwra_timings_get_Rx_chain_delay() +
1092 hwll_dev_time_from_phy(payload_end);
1093
1094 int TERM2_duration = 0; /* See Note21.b */
1095 if (rx_status.codedphy) {
1096 if (rx_status.CI == 1) {
1097 TERM2_duration = 6; //S=2 * 3bits
1098 } else {
1099 TERM2_duration = 24;//S=8 * 3bits
1100 }
1101 }
1102
1103 rx_status.CRC_End_Time = rx_status.PAYLOAD_End_Time + rx_status.CRC_duration + TERM2_duration; //Provisional value (if we are accepting the packet)
1104
1105 //Copy the whole packet (S0, lenght, S1 & payload) excluding the CRC.
1106 if (nhwra_is_ble_mode(NRF_RADIO_regs.MODE)) {
1107 if (rx_status.rx_resp.packet_size >= 5) { /*At least the header and CRC, otherwise better to not try to copy it*/
1108 ((uint8_t*)NRF_RADIO_regs.PACKETPTR)[0] = rx_buf[0];
1109 ((uint8_t*)NRF_RADIO_regs.PACKETPTR)[1] = rx_buf[1];
1110 /* We cheat a bit and copy the whole packet already (The AAR block will look in Adv packets after 64 bits)*/
1111 memcpy(&((uint8_t*)NRF_RADIO_regs.PACKETPTR)[2 + rx_status.S1Offset],
1112 &rx_buf[2] , length);
1113 }
1114 } else if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ieee802154_250Kbit) {
1115 if (rx_status.rx_resp.packet_size >= 3) { /*At least the header and CRC, otherwise better to not try to copy it*/
1116 ((uint8_t*)NRF_RADIO_regs.PACKETPTR)[0] = rx_buf[0];
1117 memcpy(&((uint8_t*)NRF_RADIO_regs.PACKETPTR)[1 + rx_status.S1Offset],
1118 &rx_buf[1] , length);
1119 }
1120 } //Eventually this should be generalized with the packet configuration
1121
1122 if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ieee802154_250Kbit) {
1123 //The real HW only copies the LQI value after the payload in this mode
1124 //Note that doing it this early is a cheat
1125 double RSSI = p2G4_RSSI_value_to_dBm(rx_status.rx_resp.rssi.RSSI) + cheat_rx_power_offset;
1126 uint8_t LQI = nhwra_dBm_to_modem_LQIformat(RSSI);
1127 //Eventually this should be generalized with the packet configuration:
1128 ((uint8_t*)NRF_RADIO_regs.PACKETPTR)[1 + rx_status.S1Offset + length] = LQI;
1129 }
1130
1131 }
1132
1133 /**
1134 * Handle all possible responses from the phy to a Rx request
1135 */
handle_Rx_response(int ret)1136 static void handle_Rx_response(int ret){
1137 if (ret == -1) {
1138 bs_trace_raw_manual_time(3,nsi_hws_get_time(),"Communication with the phy closed during Rx\n");
1139 hwll_disconnect_phy_and_exit();
1140
1141 } else if (ret == P2G4_MSG_ABORTREEVAL) {
1142
1143 phy_sync_ctrl_set_last_phy_sync_time( next_recheck_time );
1144 abort_fsm_state = Rx_Abort_reeval;
1145 nhwra_set_Timer_abort_reeval( BS_MAX(next_recheck_time,nsi_hws_get_time()) );
1146
1147 } else if ((ret == P2G4_MSG_RXV2_ADDRESSFOUND) && (radio_state == RAD_RX /*if we havent aborted*/)) {
1148
1149 bs_time_t addres_time = hwll_dev_time_from_phy(rx_status.rx_resp.rx_time_stamp); //this is the end of the sync word in air time
1150 phy_sync_ctrl_set_last_phy_sync_time(addres_time);
1151 Rx_handle_address_end_response(addres_time);
1152
1153 if ((rx_status.codedphy == false) || (rx_status.inFEC1)) {
1154 radio_sub_state = RX_WAIT_FOR_ADDRESS_END;
1155 nhwra_set_Timer_RADIO(rx_status.ADDRESS_End_Time);
1156 } else { //FEC2
1157 radio_sub_state = RX_WAIT_FOR_PAYLOAD_END;
1158 nhwra_set_Timer_RADIO(TIME_NEVER);
1159 Rx_Addr_received();
1160 nhwra_set_Timer_RADIO(rx_status.PAYLOAD_End_Time);
1161 }
1162 } else if ((ret == P2G4_MSG_RXV2_END) && (radio_state == RAD_RX /*if we havent aborted*/)) {
1163
1164 bs_time_t end_time = hwll_dev_time_from_phy(rx_status.rx_resp.end_time);
1165 phy_sync_ctrl_set_last_phy_sync_time(end_time);
1166
1167 /* P2G4_RXSTATUS_NOSYNC during a simple packet or CodedPhy FEC1 cannot really happen
1168 * As that would mean we have run out of the "infinite" scan time.
1169 * It can happen though at the start of the CodedPhy FEC2, if the transmitter aborted
1170 * before starting the FEC2 */
1171 if (rx_status.rx_resp.status == P2G4_RXSTATUS_NOSYNC) {
1172 if ((rx_status.codedphy == false) || (rx_status.inFEC1 == true)) {
1173 bs_trace_error_time_line("Unexpected not-handled path\n");
1174 }
1175 /* Otherwise we just wait for the RX_WAIT_FOR_PAYLOAD_END handling in the main RADIO FSM
1176 * A provisional PAYLOAD_End_Time was set earlier */
1177 radio_sub_state = RX_WAIT_FOR_PAYLOAD_END;
1178 nhwra_set_Timer_RADIO(rx_status.PAYLOAD_End_Time);
1179 return;
1180 } else {
1181 Rx_handle_end_response(end_time);
1182
1183 if (rx_status.inFEC1 == true) {
1184 /* To avoid issues with possible rounding errors in the phy<->dev timing conversion,
1185 * we ensure the FEC2 Rx will start in the next us in Phy time */
1186 rx_status.rx_req.start_time = rx_status.rx_resp.end_time + 1;
1187 nhwra_set_Timer_RADIO(rx_status.FEC2_start_time);
1188 }
1189 }
1190 }
1191 }
1192
1193 #if 0 //Note6.b
1194 /*
1195 * Request an immediate RSSI measurement during an Rx abort reevaluation
1196 * with the same Rx parameters as the currently ongoing reception
1197 * (the abort reevaluation will be left pending)
1198 */
1199 static p2G4_rssi_power_t Rx_abort_imm_RSSI(void) {
1200 p2G4_rssi_t rssi_req;
1201 p2G4_rssi_done_t rssi_resp;
1202 p2G4_rxv2_t *rx_req = &rx_status.rx_req;
1203
1204 //Right now, though as an immediate request this is actually ignored by the Phy:
1205 rssi_req.meas_time = hwll_phy_time_from_dev(nsi_hws_get_time());
1206 rssi_req.antenna_gain = rx_req->antenna_gain;
1207 memcpy(&rssi_req.radio_params, &rx_req->radio_params, sizeof(p2G4_radioparams_t));
1208
1209 int ret = p2G4_dev_req_imm_RSSI_nc_b(&rssi_req, &rssi_resp);
1210
1211 if (ret == -1) {
1212 bs_trace_raw_manual_time(3,nsi_hws_get_time(),"Communication with the phy closed during Rx abort reeval\n");
1213 hwll_disconnect_phy_and_exit();
1214 }
1215
1216 return rssi_resp.RSSI;
1217 }
1218 #endif
1219
1220 /**
1221 * We have reached the time in which we wanted to reevaluate if we would abort or not
1222 * so we answer to the phy with our decision
1223 */
Rx_abort_eval_respond(void)1224 static void Rx_abort_eval_respond(void) {
1225 //The abort must have been evaluated by now so we can respond to the waiting phy
1226 p2G4_abort_t *abort = &rx_status.rx_req.abort;
1227 update_abort_struct(abort, &next_recheck_time);
1228
1229 int ret = p2G4_dev_provide_new_rxv2_abort_nc_b(abort);
1230
1231 handle_Rx_response(ret);
1232 }
1233
1234 /*
1235 * Actually start the Rx in this microsecond
1236 */
start_Rx(void)1237 static void start_Rx(void) {
1238 #define RX_N_ADDR 8 /* How many addresses we can search in parallel */
1239 p2G4_address_t rx_addresses[RX_N_ADDR];
1240
1241 nhwra_check_packet_conf();
1242
1243 radio_state = RAD_RX;
1244 NRF_RADIO_regs.STATE = RAD_RX;
1245 NRF_RADIO_regs.CRCSTATUS = 0;
1246 NRF_RADIO_regs.PDUSTAT = 0;
1247
1248 if ( NRF_RADIO_regs.PCNF0 & ( RADIO_PCNF0_S1INCL_Include << RADIO_PCNF0_S1INCL_Pos ) ){
1249 rx_status.S1Offset = 1; /*1 byte offset in RAM (S1 length > 8 not supported)*/
1250 } else {
1251 rx_status.S1Offset = 0;
1252 }
1253
1254 rx_status.codedphy = false;
1255 rx_status.inFEC1 = false;
1256 rx_status.CI_error = false;
1257 rx_status.CI = 0;
1258
1259 if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_1Mbit) {
1260 bits_per_us = 1;
1261 } else if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_2Mbit) {
1262 bits_per_us = 2;
1263 } else if ((NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_LR125Kbit)
1264 || (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_LR500Kbit)) {
1265 bits_per_us = 0.125; /* For FEC1 part */
1266 rx_status.codedphy = true;
1267 rx_status.inFEC1 = true;
1268 } else if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ieee802154_250Kbit) {
1269 bits_per_us = 0.25;
1270 }
1271 rx_status.CRC_duration = nhwra_get_crc_length()*8/bits_per_us;
1272 rx_status.CRC_OK = false;
1273 rx_status.rx_resp.status = P2G4_RXSTATUS_NOSYNC;
1274
1275 if (rx_status.codedphy) {
1276 nhwra_prep_rx_request_FEC1(&rx_status.rx_req_fec1, rx_addresses);
1277 update_abort_struct(&rx_status.rx_req_fec1.abort, &next_recheck_time);
1278 }
1279 nhwra_prep_rx_request(&rx_status.rx_req, rx_addresses);
1280 update_abort_struct(&rx_status.rx_req.abort, &next_recheck_time);
1281
1282 //attempt to receive
1283 int ret;
1284 if (rx_status.codedphy) {
1285 ret = p2G4_dev_req_rxv2_nc_b(&rx_status.rx_req_fec1, rx_addresses,
1286 &rx_status.rx_resp, &rx_pkt_buffer_ptr,
1287 _NRF_MAX_PACKET_SIZE);
1288 } else {
1289 ret = p2G4_dev_req_rxv2_nc_b(&rx_status.rx_req, rx_addresses,
1290 &rx_status.rx_resp,&rx_pkt_buffer_ptr,
1291 _NRF_MAX_PACKET_SIZE);
1292 }
1293
1294 radio_sub_state = SUB_STATE_INVALID;
1295 nhwra_set_Timer_RADIO(TIME_NEVER);
1296
1297 handle_Rx_response(ret);
1298 }
1299
1300 /*
1301 * Start the Rx for a CodedPhy FEC2 packet part in this microsecond
1302 */
start_Rx_FEC2(void)1303 static void start_Rx_FEC2(void) {
1304
1305 rx_status.inFEC1 = false;
1306
1307 if (rx_status.CI == 0) {
1308 rx_status.rx_req.coding_rate = 8;
1309 //error_calc_rate & header_duration preset in nhwra_prep_rx_request() are already correct
1310 } else { //0b01
1311 bits_per_us = 0.5;
1312 rx_status.rx_req.coding_rate = 2;
1313 rx_status.rx_req.error_calc_rate = 500000;
1314 rx_status.rx_req.header_duration = 2*8*2 /* 2 bytes at 500kbps */;
1315 }
1316 /* rx_req.start_time was set based on the FEC1 end */
1317 rx_status.rx_req.pream_and_addr_duration = 0;
1318 rx_status.rx_req.n_addr = 0;
1319 rx_status.rx_req.scan_duration = 1;
1320 rx_status.rx_req.prelocked_tx = true;
1321
1322 rx_status.CRC_duration = nhwra_get_crc_length()*8/bits_per_us;
1323
1324 update_abort_struct(&rx_status.rx_req.abort, &next_recheck_time);
1325
1326 int ret;
1327
1328 ret = p2G4_dev_req_rxv2_nc_b(&rx_status.rx_req, NULL,
1329 &rx_status.rx_resp, &rx_pkt_buffer_ptr,
1330 _NRF_MAX_PACKET_SIZE);
1331
1332 handle_Rx_response(ret);
1333 }
1334
1335 /**
1336 * This function is called at the time when the Packet address* would have been
1337 * completely received for simple packets, AND at the beginning of the FEC2
1338 * for CodedPhy packets.
1339 * (* at the time of the end of the last bit of the packet address)
1340 * To continue processing the reception (the Phy was left waiting for a response)
1341 *
1342 * Note that libPhyCom has already copied the whole packet into the input buffer
1343 */
Rx_Addr_received(void)1344 static void Rx_Addr_received(void) {
1345
1346 bool accept_packet = !rx_status.packet_rejected;
1347
1348 if (rx_status.codedphy == false || rx_status.inFEC1 == false) {
1349 NRF_RADIO_regs.RXMATCH = 0; //The only we support so far
1350
1351 if (NRF_RADIO_regs.DACNF & 0xFF) { /*If any of the addresses for device address match is enabled*/
1352 /*
1353 * NOTE: we cheat and we already check the advertisement addresses and
1354 * raise the event, even though we should wait for 16 + 48 bits more
1355 *
1356 * If this is a problem, add a new timer and Rx state and delay raising the event
1357 * until then
1358 */
1359 nhw_radio_device_address_match(rx_buf);
1360 }
1361 }
1362
1363 update_abort_struct(&rx_status.rx_req.abort, &next_recheck_time);
1364 int ret = p2G4_dev_rxv2_cont_after_addr_nc_b(accept_packet, &rx_status.rx_req.abort);
1365
1366 if ( accept_packet ){ /* Always true for CodedPhy FEC1 */
1367 handle_Rx_response(ret);
1368 } else {
1369 //We said we don't 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
1370
1371 //We do what would correspond to Rx_handle_end_response() as it won't get called
1372 NRF_RADIO_regs.RXCRC = nhwra_get_rx_crc_value(rx_buf, rx_status.rx_resp.packet_size);
1373 #if !NHW_RADIO_IS_54
1374 //The 54 CCM is triggered through the DPPI like in reality
1375 nhw_ccm_radio_received_packet(!rx_status.CRC_OK);
1376 #endif
1377 }
1378 }
1379
1380 /**
1381 * Check if the address in the received (advertisement) packet
1382 * matches one configured in the DAP/DAB registers as set by DACNF
1383 *
1384 * If it does, it sets appropriately the DAI register,
1385 * in any case, it generates the DEVMATCH and DEVMISS signals accordingly
1386 *
1387 * Note that, as specified in the infocenter documentation,
1388 * the address is assumed to be the first 48 bits after the 2 byte header
1389 * and the TxAddr bit to be 7th bit in 1st header byte as per the BT Core spec.
1390 */
nhw_radio_device_address_match(uint8_t rx_buf[])1391 static void nhw_radio_device_address_match(uint8_t rx_buf[]) {
1392 bool match_found = false;
1393 bool nomatch;
1394 int TxAdd;
1395
1396 for (int i = 0 ; i < 8; i++) {
1397 if (((NRF_RADIO_regs.DACNF >> i) & 1) == 0 ) {
1398 continue;
1399 }
1400
1401 TxAdd = (NRF_RADIO_regs.DACNF >> (i + 8)) & 1;
1402
1403 if (TxAdd != ((rx_buf[0] >> 6) & 1) ) {
1404 continue;
1405 }
1406
1407 nomatch = (*(uint32_t *)(rx_buf + 2) != NRF_RADIO_regs.DAB[i]);
1408 uint32_t DAP = NRF_RADIO_regs.DAP[i] & UINT16_MAX;
1409 nomatch |= (*(uint16_t *)(rx_buf + 6) != DAP);
1410
1411 if (nomatch) {
1412 continue;
1413 }
1414
1415 match_found = true;
1416 NRF_RADIO_regs.DAI = i;
1417 break;
1418 }
1419
1420 if (match_found) {
1421 nhw_RADIO_signal_EVENTS_DEVMATCH(0);
1422 } else {
1423 nhw_RADIO_signal_EVENTS_DEVMISS(0);
1424 }
1425 }
1426
CCA_handle_end_response(void)1427 static void CCA_handle_end_response(void) {
1428 //Depending on mode, set status and registers
1429 //raising CCAIDLE, CCABUSY or EDEND will happen in the correct time in the main machine
1430
1431 if (cca_status.CCA_notED) { //End a CCA procedure
1432 uint CCAMode = (NRF_RADIO_regs.CCACTRL & RADIO_CCACTRL_CCAMODE_Msk) >> RADIO_CCACTRL_CCAMODE_Pos;
1433
1434 if ((CCAMode == RADIO_CCACTRL_CCAMODE_EdMode)
1435 || (CCAMode == RADIO_CCACTRL_CCAMODE_EdModeTest1)) {
1436 cca_status.is_busy = cca_status.cca_resp.rssi_overthreshold;
1437 } else if (CCAMode == RADIO_CCACTRL_CCAMODE_CarrierMode) {
1438 cca_status.is_busy = cca_status.cca_resp.mod_found;
1439 } else if (CCAMode == RADIO_CCACTRL_CCAMODE_CarrierAndEdMode) {
1440 cca_status.is_busy = cca_status.cca_resp.mod_found
1441 && cca_status.cca_resp.rssi_overthreshold;
1442 } else if (CCAMode == RADIO_CCACTRL_CCAMODE_CarrierOrEdMode) {
1443 cca_status.is_busy = cca_status.cca_resp.mod_found
1444 || cca_status.cca_resp.rssi_overthreshold;
1445 } else {
1446 bs_trace_error_time_line("%s, CCAMODE=%i suppport not yet implemented\n",
1447 __func__, CCAMode);
1448 }
1449 } else { // Ending an ED procedure
1450 double RSSI = p2G4_RSSI_value_to_dBm(cca_status.cca_resp.RSSI_max) + cheat_rx_power_offset;
1451 NRF_RADIO_regs.EDSAMPLE = nhwra_dBm_to_modem_LQIformat(RSSI);
1452 }
1453 }
1454
1455 /**
1456 * Handle all possible responses to a CCA request from the Phy
1457 */
handle_CCA_response(int ret)1458 static void handle_CCA_response(int ret){
1459 if (ret == -1){
1460 bs_trace_raw_manual_time(3,nsi_hws_get_time(),"The Phy disconnected us during a CCA procedure\n");
1461 hwll_disconnect_phy_and_exit();
1462 } else if ( ret == P2G4_MSG_CCA_END ) {
1463 bs_time_t end_time = hwll_dev_time_from_phy(cca_status.cca_resp.end_time);
1464 phy_sync_ctrl_set_last_phy_sync_time( end_time );
1465 cca_status.CCA_end_time = end_time;
1466 if (radio_state == RAD_CCA_ED) { /*if we haven't aborted*/
1467 nhwra_set_Timer_RADIO(cca_status.CCA_end_time);
1468 }
1469 CCA_handle_end_response();
1470 } else if ( ret == P2G4_MSG_ABORTREEVAL ) {
1471 phy_sync_ctrl_set_last_phy_sync_time( next_recheck_time );
1472 abort_fsm_state = CCA_Abort_reeval;
1473 nhwra_set_Timer_abort_reeval(next_recheck_time);
1474 }
1475 }
1476
1477 /**
1478 * We have reached the time in which we wanted to reevaluate if we would abort or not
1479 * so we answer to the Phy with our decision
1480 */
CCA_abort_eval_respond(void)1481 static void CCA_abort_eval_respond(void) {
1482 //The abort must have been evaluated by now so we can respond to the waiting phy
1483 p2G4_abort_t *abort = &cca_status.cca_req.abort;
1484
1485 update_abort_struct(abort, &next_recheck_time);
1486
1487 int ret = p2G4_dev_provide_new_cca_abort_nc_b(abort);
1488
1489 handle_CCA_response(ret);
1490 }
1491
1492 /**
1493 * Start CCA or ED procedure right now.
1494 * input: CCA_not_ED = 1 for CCA, 0 for ED
1495 */
start_CCA_ED(bool CCA_not_ED)1496 static void start_CCA_ED(bool CCA_not_ED){
1497
1498 radio_state = RAD_CCA_ED;
1499
1500 cca_status.CCA_notED = CCA_not_ED;
1501 cca_status.is_busy = false;
1502
1503 nhwra_prep_cca_request(&cca_status.cca_req, CCA_not_ED, cheat_rx_power_offset);
1504
1505 update_abort_struct(&cca_status.cca_req.abort, &next_recheck_time);
1506
1507 //Expected end time; note that it may be shorter if detect over threshold is set
1508 cca_status.CCA_end_time = nsi_hws_get_time() + cca_status.cca_req.scan_duration;
1509 nhwra_set_Timer_RADIO(cca_status.CCA_end_time);
1510
1511 //Request the CCA from the Phy:
1512 int ret = p2G4_dev_req_cca_nc_b(&cca_status.cca_req, &cca_status.cca_resp);
1513 handle_CCA_response(ret);
1514 }
1515
hw_radio_testcheat_set_rx_power_gain(double power_offset)1516 void hw_radio_testcheat_set_rx_power_gain(double power_offset){
1517 cheat_rx_power_offset = power_offset;
1518 }
1519