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 * This file includes miscellaneous utility functions used by the RADIO model
8 * but no significant logic *
9 */
10 #include <stdint.h>
11 #include <string.h>
12 #include "bs_tracing.h"
13 #include "bs_utils.h"
14 #include "bs_pc_2G4.h"
15 #include "bs_pc_2G4_utils.h"
16 #include "NHW_common_types.h"
17 #include "NHW_config.h"
18 #include "NHW_peri_types.h"
19 #include "NHW_RADIO.h"
20 #include "NHW_RADIO_priv.h"
21 #include "NHW_RADIO_timings.h"
22 #include "NRF_HWLowL.h"
23 #include "nsi_hw_scheduler.h"
24
25 extern NRF_RADIO_Type NRF_RADIO_regs;
26 static double cheat_tx_power_offset;
27
nrfra_check_crc_conf_ble(void)28 static void nrfra_check_crc_conf_ble(void) {
29 if ( (NRF_RADIO_regs.CRCCNF & RADIO_CRCCNF_LEN_Msk)
30 != (RADIO_CRCCNF_LEN_Three << RADIO_CRCCNF_LEN_Pos) ) {
31 bs_trace_error_line_time(
32 "NRF_RADIO: CRCCNF Only 3 bytes CRC is supported in BLE mode (CRCCNF=%u)\n",
33 NRF_RADIO_regs.CRCCNF & RADIO_CRCCNF_LEN_Msk);
34 }
35 }
36
nrfra_check_pcnf1_ble(void)37 static void nrfra_check_pcnf1_ble(void) {
38 int checked, check;
39 checked = NRF_RADIO_regs.PCNF1 &
40 ( RADIO_PCNF1_WHITEEN_Msk
41 | RADIO_PCNF1_ENDIAN_Msk
42 | RADIO_PCNF1_BALEN_Msk
43 | RADIO_PCNF1_STATLEN_Msk );
44
45 check = (1 << RADIO_PCNF1_WHITEEN_Pos)
46 | (RADIO_PCNF1_ENDIAN_Little << RADIO_PCNF1_ENDIAN_Pos)
47 | (3 << RADIO_PCNF1_BALEN_Pos) //4 bytes address
48 | (0 << RADIO_PCNF1_STATLEN_Pos);
49
50 if (checked != check) {
51 bs_trace_error_line_time(
52 "%s w LR|1|2Mbps BLE modulation only the BLE packet format is supported so far (PCNF1=%u)\n",
53 __func__, NRF_RADIO_regs.PCNF1);
54 }
55 }
56
nrfra_check_ble1M_conf(void)57 static void nrfra_check_ble1M_conf(void){
58 int checked =NRF_RADIO_regs.PCNF0 &
59 (RADIO_PCNF0_PLEN_Msk
60 | RADIO_PCNF0_S1LEN_Msk
61 | RADIO_PCNF0_S0LEN_Msk
62 | RADIO_PCNF0_LFLEN_Msk);
63
64 int check = ( ( 8 << RADIO_PCNF0_LFLEN_Pos )
65 | ( 1 << RADIO_PCNF0_S0LEN_Pos )
66 | ( 0 << RADIO_PCNF0_S1LEN_Pos )
67 | ( RADIO_PCNF0_PLEN_8bit << RADIO_PCNF0_PLEN_Pos ) );
68
69 if (checked != check) {
70 bs_trace_error_line_time(
71 "NRF_RADIO: For 1 Mbps only BLE packet format is supported so far (PCNF0=%u)\n",
72 NRF_RADIO_regs.PCNF0);
73 }
74
75 nrfra_check_pcnf1_ble();
76 nrfra_check_crc_conf_ble();
77 }
78
79
nrfra_check_ble2M_conf(void)80 static void nrfra_check_ble2M_conf(void){
81 int checked =NRF_RADIO_regs.PCNF0 &
82 (RADIO_PCNF0_PLEN_Msk
83 | RADIO_PCNF0_S1LEN_Msk
84 | RADIO_PCNF0_S0LEN_Msk
85 | RADIO_PCNF0_LFLEN_Msk);
86
87 int check = ( ( 8 << RADIO_PCNF0_LFLEN_Pos )
88 | ( 1 << RADIO_PCNF0_S0LEN_Pos )
89 | ( 0 << RADIO_PCNF0_S1LEN_Pos )
90 | ( RADIO_PCNF0_PLEN_16bit << RADIO_PCNF0_PLEN_Pos ) );
91
92 if (checked != check) {
93 bs_trace_error_line_time(
94 "NRF_RADIO: For 2 Mbps only BLE packet format is supported so far (PCNF0=%u)\n",
95 NRF_RADIO_regs.PCNF0);
96 }
97
98 nrfra_check_pcnf1_ble();
99 nrfra_check_crc_conf_ble();
100 }
101
nrfra_check_bleLR_conf(void)102 static void nrfra_check_bleLR_conf(void){
103
104 int checked =NRF_RADIO_regs.PCNF0 &
105 ( RADIO_PCNF0_TERMLEN_Msk
106 | RADIO_PCNF0_PLEN_Msk
107 | RADIO_PCNF0_CILEN_Msk
108 | RADIO_PCNF0_S1LEN_Msk
109 | RADIO_PCNF0_S0LEN_Msk
110 | RADIO_PCNF0_LFLEN_Msk);
111
112 int check = ( ( 8 << RADIO_PCNF0_LFLEN_Pos )
113 | ( 1 << RADIO_PCNF0_S0LEN_Pos )
114 | ( 0 << RADIO_PCNF0_S1LEN_Pos )
115 | ( 2 << RADIO_PCNF0_CILEN_Pos )
116 | ( RADIO_PCNF0_PLEN_LongRange << RADIO_PCNF0_PLEN_Pos )
117 | ( 3 << RADIO_PCNF0_TERMLEN_Pos) );
118
119 if (checked != check) {
120 bs_trace_error_line_time(
121 "NRF_RADIO: For LR BLE mode only BLE packet format is supported so far (PCNF0=%u)\n",
122 NRF_RADIO_regs.PCNF0);
123 }
124
125 nrfra_check_pcnf1_ble();
126 nrfra_check_crc_conf_ble();
127 }
128
129
nrfra_check_802154_conf(void)130 static void nrfra_check_802154_conf(void){
131 int checked, check;
132
133 //Overall packet structure:
134 checked =NRF_RADIO_regs.PCNF0 &
135 ( RADIO_PCNF0_TERMLEN_Msk
136 | RADIO_PCNF0_CRCINC_Msk
137 | RADIO_PCNF0_PLEN_Msk
138 | RADIO_PCNF0_CILEN_Msk
139 | RADIO_PCNF0_S1INCL_Msk
140 | RADIO_PCNF0_S1LEN_Msk
141 | RADIO_PCNF0_S0LEN_Msk
142 | RADIO_PCNF0_LFLEN_Msk);
143
144 check = (
145 //TERM = 0
146 RADIO_PCNF0_CRCINC_Msk
147 | ( RADIO_PCNF0_PLEN_32bitZero << RADIO_PCNF0_PLEN_Pos )
148 //CILEN = 0
149 //S1INCL = 0
150 | ( 0 << RADIO_PCNF0_S1LEN_Pos )
151 | ( 0 << RADIO_PCNF0_S0LEN_Pos )
152 | ( 8 << RADIO_PCNF0_LFLEN_Pos )
153 );
154 if (checked != check) {
155 bs_trace_error_line_time(
156 "%s w 15.4 modulation only the 802154 packet format is supported so far (PCNF0=%u)\n",
157 __func__, NRF_RADIO_regs.PCNF0);
158 }
159
160 checked = NRF_RADIO_regs.PCNF1 &
161 ( RADIO_PCNF1_WHITEEN_Msk
162 | RADIO_PCNF1_ENDIAN_Msk
163 | RADIO_PCNF1_BALEN_Msk
164 | RADIO_PCNF1_STATLEN_Msk );
165
166 check = (0 << RADIO_PCNF1_WHITEEN_Pos)
167 | (RADIO_PCNF1_ENDIAN_Little << RADIO_PCNF1_ENDIAN_Pos)
168 | (0 << RADIO_PCNF1_BALEN_Pos) // => 1 byte for SFD
169 | (0 << RADIO_PCNF1_STATLEN_Pos);
170
171 if (checked != check) {
172 bs_trace_error_line_time(
173 "%s w 15.4 modulation only the 802154 packet format is supported so far (PCNF1=%u)\n",
174 __func__, NRF_RADIO_regs.PCNF1);
175 }
176
177 //CRC:
178 if ( (NRF_RADIO_regs.CRCCNF & RADIO_CRCCNF_LEN_Msk)
179 != (RADIO_CRCCNF_LEN_Two << RADIO_CRCCNF_LEN_Pos) ) {
180 bs_trace_error_line_time(
181 "%s CRCCNF Only 2 bytes CRC is supported in 15.4 mode (CRCCNF=%u)\n",
182 __func__,
183 NRF_RADIO_regs.CRCCNF & RADIO_CRCCNF_LEN_Msk);
184 }
185 }
186
187 /*
188 * A few checks to ensure the model is only used with the currently supported packet format
189 */
nhwra_check_packet_conf(void)190 void nhwra_check_packet_conf(void){
191
192 if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_1Mbit) {
193 nrfra_check_ble1M_conf();
194 } else if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_2Mbit) {
195 nrfra_check_ble2M_conf();
196 } else if ((NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_LR125Kbit)
197 || (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_LR500Kbit)){
198 nrfra_check_bleLR_conf();
199 } else if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ieee802154_250Kbit) {
200 nrfra_check_802154_conf();
201 } else {
202 bs_trace_error_line_time(
203 "NRF_RADIO: Only 1&2 Mbps BLE & 802.15.4 packet formats supported so far (MODE=%u)\n",
204 NRF_RADIO_regs.MODE);
205 }
206 }
207
nhwra_RSSI_value_to_modem_format(double rssi_value)208 uint32_t nhwra_RSSI_value_to_modem_format(double rssi_value){
209 rssi_value = -BS_MAX(rssi_value,-127);
210 rssi_value = BS_MAX(rssi_value,0);
211 return (uint32_t)rssi_value;
212 }
213
nhwra_dBm_to_modem_LQIformat(double rssi_value)214 uint8_t nhwra_dBm_to_modem_LQIformat(double rssi_value){
215 //PRF[dBm] = ED_RSSIOFFS + VALHARDWARE
216 //=> VALHARDWARE = PRF[dBm] - ED_RSSIOFFS
217 rssi_value -= NHW_RADIO_ED_RSSIOFFS;
218 rssi_value = BS_MAX(rssi_value,0);
219 rssi_value = BS_MIN(rssi_value,255);
220 return (uint8_t)rssi_value;
221 }
222
nrfra_LQIformat_to_dBm(uint value)223 double nrfra_LQIformat_to_dBm(uint value){
224 //PRF[dBm] = ED_RSSIOFFS + VALHARDWARE
225 return (double)value + NHW_RADIO_ED_RSSIOFFS;
226 }
227
nhwra_is_HW_TIFS_enabled(void)228 int nhwra_is_HW_TIFS_enabled(void) {
229
230 bool Fast_RU =
231 #if NHW_RADIO_IS_54
232 NRF_RADIO_regs.TIMING & RADIO_TIMING_RU_Msk;
233 #else
234 NRF_RADIO_regs.MODECNF0 & RADIO_MODECNF0_RU_Msk;
235 #endif
236
237 #if NHW_RADIO_IS_54
238 if ( ( NRF_RADIO_regs.SHORTS & RADIO_SHORTS_PHYEND_DISABLE_Msk )
239 #else
240 if ( ( NRF_RADIO_regs.SHORTS & RADIO_SHORTS_END_DISABLE_Msk )
241 #endif
242 && ( ( NRF_RADIO_regs.SHORTS & RADIO_SHORTS_DISABLED_RXEN_Msk )
243 || ( NRF_RADIO_regs.SHORTS & RADIO_SHORTS_DISABLED_TXEN_Msk ) )
244 && (Fast_RU == 0) )
245 {
246 return 1;
247 }
248 return 0;
249 }
250
nhwra_get_address(uint logical_addr)251 static uint64_t nhwra_get_address(uint logical_addr) {
252 uint64_t address;
253
254 if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ieee802154_250Kbit) {
255 address = NRF_RADIO_regs.SFD & RADIO_SFD_SFD_Msk;
256 } else {
257 if (logical_addr > 7) {
258 bs_trace_error_time_line("programming error: Logical address out of range (%u > 7)\n", logical_addr);
259 }
260 int BALEN_bits = 8*((NRF_RADIO_regs.PCNF1 & RADIO_PCNF1_BALEN_Msk) >> RADIO_PCNF1_BALEN_Pos);
261 uint32_t base;
262
263 if (logical_addr == 0) {
264 base = NRF_RADIO_regs.BASE0;
265 } else {
266 base = NRF_RADIO_regs.BASE1;
267 }
268
269 uint32_t *prefix_ptr = (uint32_t *)&NRF_RADIO_regs.PREFIX0;
270 uint64_t prefix = prefix_ptr[logical_addr >> 2] >> (8*(logical_addr & 0x3));
271
272 address = ((prefix & RADIO_PREFIX0_AP0_Msk) << BALEN_bits)
273 | (base >> (32 - BALEN_bits));
274 }
275 return address;
276 }
277
nhra_modulation_from_mode(uint32_t MODE)278 static p2G4_modulation_t nhra_modulation_from_mode(uint32_t MODE) {
279 p2G4_modulation_t modulation;
280 if (MODE == RADIO_MODE_MODE_Ble_1Mbit) {
281 modulation = P2G4_MOD_BLE;
282 } else if (MODE == RADIO_MODE_MODE_Ble_2Mbit) {
283 modulation = P2G4_MOD_BLE2M;
284 } else if (MODE == RADIO_MODE_MODE_Ieee802154_250Kbit) {
285 modulation = P2G4_MOD_154_250K_DSS;
286 } else if ((MODE == RADIO_MODE_MODE_Ble_LR125Kbit)
287 || (MODE == RADIO_MODE_MODE_Ble_LR500Kbit)) {
288 modulation = P2G4_MOD_BLE_CODED;
289 } else {
290 bs_trace_error_time_line("programming error: Unsupported MODE %u\n", MODE);
291 }
292 return modulation;
293 }
294
nhwra_is_ble_mode(uint32_t MODE)295 bool nhwra_is_ble_mode(uint32_t MODE) {
296 if ((MODE == RADIO_MODE_MODE_Ble_1Mbit)
297 || (MODE == RADIO_MODE_MODE_Ble_2Mbit)
298 || (MODE == RADIO_MODE_MODE_Ble_LR125Kbit)
299 || (MODE == RADIO_MODE_MODE_Ble_LR500Kbit)) {
300 return true;
301 } else {
302 return false;
303 }
304 }
305
306 /**
307 * Prepare a Phy Rxv2 request structure
308 * based on the radio registers configuration
309 * (For CodedPhy only for the FEC2 part, and only provisional content assuming S=8)
310 *
311 * Note: The abort substructure is NOT filled.
312 */
nhwra_prep_rx_request(p2G4_rxv2_t * rx_req,p2G4_address_t * rx_addresses)313 void nhwra_prep_rx_request(p2G4_rxv2_t *rx_req, p2G4_address_t *rx_addresses) {
314
315 //TOLOW: Add support for other packet formats and bitrates
316 uint8_t preamble_length = 0;
317 uint8_t address_length = 0;
318 uint8_t header_length = 0;
319 bs_time_t pre_trunc = 0;
320 uint16_t sync_threshold = 0;
321
322 uint32_t freq_off = NRF_RADIO_regs.FREQUENCY & RADIO_FREQUENCY_FREQUENCY_Msk;
323 double bits_per_us = 0;
324
325 rx_addresses[0] = nhwra_get_address(0); /* We only support RXADDRESSES == 0x01 by now */
326
327 rx_req->radio_params.modulation = nhra_modulation_from_mode(NRF_RADIO_regs.MODE);
328
329 if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_1Mbit) {
330 //Note that we only support BLE packet formats by now (so we ignore the configuration of the preamble and just assume it is what it needs to be)
331 //we rely on the Tx side error/warning being enough to warn users that we do not support other formats
332 preamble_length = 1; //1 byte
333 address_length = 4;
334 header_length = 2;
335 bits_per_us = 1;
336 pre_trunc = 0; //The modem can lose a lot of preamble and sync (~7us), we leave it as 0 by now to avoid a behavior change
337 sync_threshold = 2; //(<) we tolerate less than 2 errors in the preamble and sync word together (old number, probably does not reflect the actual RADIO performance)
338 } else if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_2Mbit) {
339 preamble_length = 2; //2 bytes
340 address_length = 4;
341 header_length = 2;
342 bits_per_us = 2;
343 pre_trunc = 0; //The modem can lose a lot of preamble and sync (~7us), we leave it as 0 by now to avoid a behavior change
344 sync_threshold = 2;
345 } else if ((NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_LR125Kbit)
346 || (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ble_LR500Kbit)) {
347 /* For the FEC2 part */
348 preamble_length = 0;
349 address_length = 0;
350 header_length = 2;
351 bits_per_us = 0.125; /* Provisional value assuming S=8 */
352 pre_trunc = 0;
353 sync_threshold = 0xFFFF;
354 } else if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ieee802154_250Kbit) {
355 preamble_length = 4;
356 address_length = 1;
357 header_length = 0;
358 bits_per_us = 0.25;
359 pre_trunc = 104; //The modem seems to be able to sync with just 3 sybmols of the preamble == lossing 13symbols|26bits|104us
360 sync_threshold = 0;
361 }
362
363 rx_req->coding_rate = 0;
364
365 p2G4_freq_t center_freq;
366 p2G4_freq_from_d(freq_off, 1, ¢er_freq);
367 rx_req->radio_params.center_freq = center_freq;
368
369 rx_req->error_calc_rate = bits_per_us*1000000;
370 rx_req->antenna_gain = 0;
371
372 rx_req->header_duration = header_length*8/bits_per_us;
373 rx_req->header_threshold = 0; //(<=) we tolerate 0 bit errors in the header which will be found in the crc (we may want to tune this)
374 rx_req->sync_threshold = sync_threshold;
375 rx_req->acceptable_pre_truncation = pre_trunc;
376
377 rx_req->n_addr = 1;
378
379 rx_req->pream_and_addr_duration = (preamble_length + address_length)*8/bits_per_us;
380
381 rx_req->scan_duration = UINT32_MAX;
382 rx_req->forced_packet_duration = UINT32_MAX; //we follow the transmitted packet (assuming no length errors by now)
383
384 rx_req->start_time = hwll_phy_time_from_dev(nsi_hws_get_time());
385
386 rx_req->resp_type = 0;
387 rx_req->prelocked_tx = false;
388 }
389
390 /**
391 * Prepare a Phy Rxv2 request structure for CodedPhy's FEC1 part
392 * based on the radio registers configuration.
393 *
394 * Note: The abort substructure is NOT filled.
395 */
nhwra_prep_rx_request_FEC1(p2G4_rxv2_t * rx_req,p2G4_address_t * rx_addresses)396 void nhwra_prep_rx_request_FEC1(p2G4_rxv2_t *rx_req, p2G4_address_t *rx_addresses) {
397
398 uint32_t freq_off = NRF_RADIO_regs.FREQUENCY & RADIO_FREQUENCY_FREQUENCY_Msk;
399 p2G4_freq_t center_freq;
400
401 p2G4_freq_from_d(freq_off, 1, ¢er_freq);
402 rx_req->radio_params.center_freq = center_freq;
403
404 rx_addresses[0] = nhwra_get_address(0); /* We only support RXADDRESSES == 0x01 by now */
405 rx_req->n_addr = 1;
406
407 rx_req->radio_params.modulation = nhra_modulation_from_mode(NRF_RADIO_regs.MODE);
408
409 rx_req->antenna_gain = 0;
410
411 rx_req->coding_rate = 8;
412
413 rx_req->error_calc_rate = 125000;
414
415 rx_req->header_duration = 16; /* CI duration */
416 rx_req->header_threshold = 0xFFFF; /* We don't want "header"/CI errors in the FEC1 part in any case for design simplicity, we just check the "packet error" result */
417 rx_req->sync_threshold = 2;
418 rx_req->acceptable_pre_truncation = 65; /* It seems the radio manages with ~15us of coded phy preamble in good signal conditions */
419
420 rx_req->pream_and_addr_duration = 80 + 256;
421
422 rx_req->scan_duration = UINT32_MAX;
423 rx_req->forced_packet_duration = UINT32_MAX; //we follow the transmitted packet (assuming no length errors by now)
424
425 rx_req->start_time = hwll_phy_time_from_dev(nsi_hws_get_time());
426
427 rx_req->resp_type = 0;
428 }
429
nhwra_tx_power_from_reg(void)430 static double nhwra_tx_power_from_reg(void) {
431 double TxPower;
432 #if !NHW_RADIO_IS_54
433 TxPower = (int8_t)( NRF_RADIO_regs.TXPOWER & RADIO_TXPOWER_TXPOWER_Msk); //the cast is to sign extend it
434 //Note: For 5340, VREQCTRL effect not yet accounted for
435 #else
436 #if defined(NRF54L15)
437 switch (NRF_RADIO_regs.TXPOWER) {
438 case 0x3F : return 10;
439 case 0x39 : return 9 ;
440 case 0x33 : return 8 ;
441 case 0x2D : return 7 ;
442 case 0x28 : return 6 ;
443 case 0x23 : return 5 ;
444 case 0x1F : return 4 ;
445 case 0x1B : return 3 ;
446 case 0x18 : return 2 ;
447 case 0x15 : return 1 ;
448 case 0x13 : return 0 ;
449 case 0x11 : return -1 ;
450 case 0xF : return -2 ;
451 case 0xD : return -3 ;
452 case 0xB : return -4 ;
453 case 0xA : return -5 ;
454 case 0x9 : return -6 ;
455 case 0x8 : return -7 ;
456 case 0x7 : return -8 ;
457 case 0x6 : return -9 ;
458 case 0x5 : return -10;
459 case 0x4 : return -12;
460 case 0x3 : return -14;
461 case 0x2 : return -16;
462 case 0x1 : return -20;
463 case 0x0 : return -26;
464 case 0x130: return -40;
465 case 0x110: return -46;
466 default:
467 bs_trace_warning_time_line("Unknown TXPOWER setting for this radio\n");
468 return 0;
469 }
470 #elif defined(NRF54H20)
471 switch (NRF_RADIO_regs.TXPOWER) {
472 case 0x1F: return 10;
473 case 0x1D: return 9 ;
474 case 0x1C: return 8 ;
475 case 0x1B: return 7 ;
476 case 0x1A: return 6 ;
477 case 0x19: return 5 ;
478 case 0x18: return 4 ;
479 case 0x17: return 3 ;
480 case 0x16: return 2 ;
481 case 0xF : return 1 ;
482 case 0xE : return 0 ;
483 case 0xD : return -1;
484 case 0xC : return -2;
485 case 0xB : return -4;
486 case 0xA : return -8;
487 case 0x9 : return -1;
488 case 0x8 : return -1;
489 case 0x3 : return -2;
490 case 0x2 : return -3;
491 case 0x1 : return -4;
492 case 0x0 : return -7;
493 default:
494 bs_trace_warning_time_line("Unknown TXPOWER setting for this radio\n");
495 return 0;
496 }
497 #error "Tx power mapping missing for this device"
498 #endif
499 #endif /* !NHW_RADIO_IS_54 */
500 return TxPower;
501 }
502
503 /**
504 * Prepare a Phy Tx request structure
505 * based on the radio registers configuration.
506 *
507 * Note: The abort substructure is NOT filled.
508 */
nhwra_prep_tx_request(p2G4_txv2_t * tx_req,uint packet_size,bs_time_t packet_duration,bs_time_t start_time,uint16_t coding_rate)509 void nhwra_prep_tx_request(p2G4_txv2_t *tx_req, uint packet_size, bs_time_t packet_duration,
510 bs_time_t start_time, uint16_t coding_rate) {
511
512 tx_req->radio_params.modulation = nhra_modulation_from_mode(NRF_RADIO_regs.MODE);
513
514 tx_req->phy_address = nhwra_get_address(NRF_RADIO_regs.TXADDRESS);
515
516 {
517 double TxPower = nhwra_tx_power_from_reg();
518 tx_req->power_level = p2G4_power_from_d(TxPower + cheat_tx_power_offset); //Note that any possible Tx antenna or PA gain would need to be included here
519 }
520
521 { //Note only default freq. map supported
522 uint32_t freq_off = NRF_RADIO_regs.FREQUENCY & RADIO_FREQUENCY_FREQUENCY_Msk;
523 p2G4_freq_t center_freq;
524 p2G4_freq_from_d(freq_off, 1, ¢er_freq);
525 tx_req->radio_params.center_freq = center_freq;
526 }
527 tx_req->packet_size = packet_size; //Not including preamble or address
528
529 {
530 tx_req->start_tx_time = start_time;
531 tx_req->start_packet_time = tx_req->start_tx_time;
532 tx_req->end_tx_time = tx_req->start_tx_time + packet_duration - 1;
533 tx_req->end_packet_time = tx_req->end_tx_time;
534 }
535 tx_req->coding_rate = coding_rate;
536 }
537
538 /**
539 * Prepare a Phy CCA request structure
540 * based on the radio registers configuration.
541 *
542 * Note: The abort substructure is NOT filled.
543 */
nhwra_prep_cca_request(p2G4_cca_t * cca_req,bool CCA_not_ED,double rx_pow_offset)544 void nhwra_prep_cca_request(p2G4_cca_t *cca_req, bool CCA_not_ED, double rx_pow_offset) {
545
546 cca_req->start_time = hwll_phy_time_from_dev(nsi_hws_get_time()); //We start right now
547 cca_req->antenna_gain = 0;
548
549 uint32_t freq_off = NRF_RADIO_regs.FREQUENCY & RADIO_FREQUENCY_FREQUENCY_Msk;
550 p2G4_freq_t center_freq;
551 p2G4_freq_from_d(freq_off, 1, ¢er_freq);
552 cca_req->radio_params.center_freq = center_freq;
553
554 if (NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ieee802154_250Kbit) {
555 cca_req->radio_params.modulation = P2G4_MOD_154_250K_DSS;
556 } else {
557 bs_trace_error_line_time("CCA procedure only supported with 15.4 modulation\n");
558 }
559
560 int symbol_time = 16; //micros
561 #if NHW_RADIO_IS_54
562 uint EDPERIOD = (NRF_RADIO_regs.EDCTRL & RADIO_EDCTRL_EDPERIOD_Msk) >> RADIO_EDCTRL_EDPERIOD_Pos;
563 uint EDCNT = (NRF_RADIO_regs.EDCTRL & RADIO_EDCTRL_EDCNT_Msk) >> RADIO_EDCTRL_EDCNT_Pos;
564 uint one_scan_duration = 4*EDPERIOD;
565 #else
566 uint EDCNT = (NRF_RADIO_regs.EDCNT & RADIO_EDCNT_EDCNT_Msk) >> RADIO_EDCNT_EDCNT_Pos;
567 uint one_scan_duration = 8*symbol_time;
568 #endif
569
570 if (CCA_not_ED) { //CCA request
571 uint edthreshold = (NRF_RADIO_regs.CCACTRL & RADIO_CCACTRL_CCAEDTHRES_Msk) >> RADIO_CCACTRL_CCAEDTHRES_Pos;
572 uint CCAMode = (NRF_RADIO_regs.CCACTRL & RADIO_CCACTRL_CCAMODE_Msk) >> RADIO_CCACTRL_CCAMODE_Pos;
573 double carrier_detect_level = -110 - rx_pow_offset; //dBm : Any detectable signal by the modem
574 double edthreshold_dBm = nrfra_LQIformat_to_dBm(edthreshold) - rx_pow_offset;
575
576 cca_req->scan_duration = one_scan_duration;
577 cca_req->scan_period = cca_req->scan_duration/4; //let's measure 4 times (model design choice)
578
579 if (CCAMode == RADIO_CCACTRL_CCAMODE_EdMode) {
580 cca_req->rssi_threshold = p2G4_RSSI_value_from_dBm(edthreshold_dBm);
581 cca_req->mod_threshold = p2G4_RSSI_value_from_dBm(100/*dBm*/); //not used
582 cca_req->stop_when_found = 0;
583 } else if (CCAMode == RADIO_CCACTRL_CCAMODE_CarrierMode) {
584 cca_req->stop_when_found = 1;
585 cca_req->rssi_threshold = p2G4_RSSI_value_from_dBm(100/*dBm*/); //not used
586 cca_req->mod_threshold = p2G4_RSSI_value_from_dBm(carrier_detect_level);
587 //The Phy does not support detecting just based on something close enough in the correlator output
588 //so we ignore CCACTRL.CCACORRCNT & CCACTRL.CCACORRTHRES
589 } else if ((CCAMode == RADIO_CCACTRL_CCAMODE_CarrierAndEdMode)
590 || (CCAMode == RADIO_CCACTRL_CCAMODE_CarrierOrEdMode) ) {
591 cca_req->stop_when_found = 1;
592 cca_req->rssi_threshold = p2G4_RSSI_value_from_dBm(edthreshold_dBm);
593 cca_req->mod_threshold = p2G4_RSSI_value_from_dBm(carrier_detect_level);
594 } else if (CCAMode == RADIO_CCACTRL_CCAMODE_EdModeTest1) {
595 cca_req->rssi_threshold = p2G4_RSSI_value_from_dBm(edthreshold_dBm);
596 cca_req->mod_threshold = p2G4_RSSI_value_from_dBm(100/*dBm*/); //not used
597 cca_req->stop_when_found = 2;
598 } else {
599 bs_trace_error_time_line("%s, CCAMODE=%i support not yet implemented\n",
600 __func__, CCAMode);
601 }
602 } else { //ED request
603 cca_req->scan_duration = one_scan_duration * (EDCNT + 1);
604 cca_req->scan_period = 2 * symbol_time; //let's measure 4 times per EDCNT (model design choice)
605 cca_req->rssi_threshold = p2G4_RSSI_value_from_dBm(100/*dBm*/); //not used
606 cca_req->mod_threshold = p2G4_RSSI_value_from_dBm(100/*dBm*/); //not used
607 cca_req->stop_when_found = 0;
608 }
609 }
610
611
612 /**
613 * Return the CRC length in bytes
614 */
nhwra_get_crc_length(void)615 uint nhwra_get_crc_length(void) {
616 return (NRF_RADIO_regs.CRCCNF & RADIO_CRCCNF_LEN_Msk) >> RADIO_CRCCNF_LEN_Pos;
617 }
618
619
nhwra_get_MAXLEN(void)620 uint nhwra_get_MAXLEN(void) {
621 return (NRF_RADIO_regs.PCNF1 & RADIO_PCNF1_MAXLEN_Msk) >> RADIO_PCNF1_MAXLEN_Pos;
622 }
623
624 /*
625 * Return the payload length, NOT including the CRC length
626 * (and NOT adding S0 or S1 lengths)
627 */
nhwra_get_payload_length(uint8_t * buf)628 uint nhwra_get_payload_length(uint8_t *buf){
629 int S0Len;
630 int LFLenb, LFLenB;
631 uint payload_len = 0;
632 S0Len = (NRF_RADIO_regs.PCNF0 & RADIO_PCNF0_S0LEN_Msk) >> RADIO_PCNF0_S0LEN_Pos;
633
634 LFLenb = (NRF_RADIO_regs.PCNF0 & RADIO_PCNF0_LFLEN_Msk) >> RADIO_PCNF0_LFLEN_Pos;
635 LFLenB = (LFLenb + 7)/8;
636
637 for (int i = 0; i < LFLenB; i++){
638 payload_len += buf[S0Len+i] << i*8;
639 }
640
641 if (NRF_RADIO_regs.PCNF0 & RADIO_PCNF0_CRCINC_Msk) {
642 int crc_len = nhwra_get_crc_length();
643 if (payload_len >= crc_len) {
644 payload_len -= crc_len;
645 } else {
646 bs_trace_error_time_line("Programmed payload length (%i) smaller than CRC length (%i), "
647 "while it was configured as including the CRC.. => SW programming error\n",
648 payload_len, crc_len);
649 }
650 }
651 return payload_len;
652 }
653
nrfra_get_capped_payload_length(uint8_t * buf)654 uint nrfra_get_capped_payload_length(uint8_t *buf) {
655 uint payload_lenght = nhwra_get_payload_length(buf);
656 uint max_length = nhwra_get_MAXLEN();
657 return BS_MIN(payload_lenght, max_length);
658 }
659
660 /*
661 * Get the received CRC value from the received buffer
662 * paramters:
663 * rx_buf: Pointer to the received buffer
664 * rx_packet_size: Number of input bytes in rx_buf
665 */
nhwra_get_rx_crc_value(uint8_t * rx_buf,size_t rx_packet_size)666 uint32_t nhwra_get_rx_crc_value(uint8_t *rx_buf, size_t rx_packet_size) {
667 uint32_t crc = 0;
668 uint crc_len = nhwra_get_crc_length();
669 uint payload_len = nrfra_get_capped_payload_length(rx_buf);
670
671 //Eventually this should be generalized with the packet configuration
672 if (nhwra_is_ble_mode(NRF_RADIO_regs.MODE)
673 && ( rx_packet_size >= 5 ) ){
674 memcpy((void*)&crc, &rx_buf[2 + payload_len], crc_len);
675 } else if ((NRF_RADIO_regs.MODE == RADIO_MODE_MODE_Ieee802154_250Kbit)
676 && ( rx_packet_size >= 3 ) ){
677 memcpy((void*)&crc, &rx_buf[1 + payload_len], crc_len);
678 }
679 return crc;
680 }
681
682 /**
683 * Assemble a packet to be transmitted out thru the air into tx_buf[]
684 * Omitting the preamble and address/sync flag
685 *
686 * Return copied payload size (after S0 + len + S1) into tx_buf[]
687 * (without the CRC)
688 *
689 * Note: PCNF1.MAXLEN is taken into account to cap len
690 *
691 * Note: When adding support for CodedPhy and or other packet formats,
692 * this needs to be reworked together with the start_Tx()
693 * function, as it is all way too interdependent
694 */
nhwra_tx_copy_payload(uint8_t * tx_buf)695 uint nhwra_tx_copy_payload(uint8_t *tx_buf){
696 int S0Len, S1LenB, LFLenB; //All in bytes
697 int LFLenb, S1LenAirb;
698 int i;
699 uint payload_len;
700 int maxlen;
701
702 S0Len = (NRF_RADIO_regs.PCNF0 & RADIO_PCNF0_S0LEN_Msk) >> RADIO_PCNF0_S0LEN_Pos;
703
704
705 S1LenAirb = (NRF_RADIO_regs.PCNF0 & RADIO_PCNF0_S1LEN_Msk) >> RADIO_PCNF0_S1LEN_Pos;
706 S1LenB = (S1LenAirb + 7)/8; //This is just : S1Offset = ceil(PCNF0.S1LEN / 8)
707
708 LFLenb = (NRF_RADIO_regs.PCNF0 & RADIO_PCNF0_LFLEN_Msk) >> RADIO_PCNF0_LFLEN_Pos;
709 LFLenB = (LFLenb + 7)/8;
710
711 //copy from RAM to Tx buffer
712 i = 0;
713 if (S0Len) {
714 tx_buf[0] = ((uint8_t*)NRF_RADIO_regs.PACKETPTR)[0];
715 i++;
716 }
717 for (int j = 0; j < LFLenB; j++){ //Copy up to 2 Length bytes
718 tx_buf[i] = ((uint8_t*)NRF_RADIO_regs.PACKETPTR)[i];
719 i++;
720 }
721 int S1Off = 0;
722 if ( NRF_RADIO_regs.PCNF0 & ( RADIO_PCNF0_S1INCL_Include << RADIO_PCNF0_S1INCL_Pos ) ) {
723 if (S1LenB == 0) {
724 S1Off = 1; //We skip 1 S1 byte in RAM
725 }
726 /*
727 * If S1INCL and S1LEN > 0, the assumption is that the
728 * the size in RAM will just be the same as in air
729 * TODO: this behavior needs to be confirmed
730 */
731 }
732
733 payload_len = nhwra_get_payload_length(tx_buf);
734 /* Note that we assume if CRCINC=1, CRCLEN is deducted from the length field
735 * before capping the length to MAXLEN */
736 maxlen = nhwra_get_MAXLEN();
737 if (payload_len > maxlen) {
738 bs_trace_error_time_line("NRF_RADIO: Transmitting a packet longer than the configured MAXLEN (%i>%i). "
739 "This would truncate it and a corrupted packet will be transmitted. "
740 "Assuming this is a controller programming error, so we stop here. "
741 "If you did really intend this, please request this error to be converted into a warning "
742 "(the model handles this properly)\n", payload_len, maxlen);
743 payload_len = maxlen;
744 NRF_RADIO_regs.PDUSTAT = RADIO_PDUSTAT_PDUSTAT_Msk;
745 } else {
746 NRF_RADIO_regs.PDUSTAT = 0;
747 }
748
749 int copy_len = payload_len + S1LenB;
750 memcpy(&tx_buf[i], &((uint8_t*)NRF_RADIO_regs.PACKETPTR)[i + S1Off], copy_len);
751 return payload_len;
752 }
753
hw_radio_testcheat_set_tx_power_gain(double power_offset_i)754 void hw_radio_testcheat_set_tx_power_gain(double power_offset_i) {
755 cheat_tx_power_offset = power_offset_i;
756 }
757