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, &center_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, &center_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, &center_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, &center_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