diff --git a/doc/L1SIM.md b/doc/L1SIM.md index 7e6d893a2e..56be7f93b6 100644 --- a/doc/L1SIM.md +++ b/doc/L1SIM.md @@ -12,23 +12,29 @@ -This page is valid for the develop branch +**Note: unless you know what you are doing, you likely do not need this! +Rather, you are probably looking for the +[RFsimulator](../radio/rfsimulator/README.md)!** -**Table of Contents** +oaisim has been scraped and replaced by the same programs that are used for the +real-time operation, `lte-softmodem` and `lte-uesoftmodem`. This uses the IF4p5 +fronthaul protocol to achieve the communication. + +Context: oaisim used to be a simulation mode inside OAI to emulate an eNB and +multiple UEs. [[_TOC_]] -The old oaisim is dead! Long live oaisim! :) +# Build -If you are looking for a description of the old oaisim (which is still available in some branches/tags), please see [here](OpenAirLTEEmulation) and [here](how-to-run-oaisim-with-multiple-ue). +Build eNB/UE as normal, as also described in [How to build the eNB and the UE](./BUILD.md): +```bash +./build_oai -c --ninja --eNB --UE +``` -oaisim has been scraped and replaced by the same programs that are used for the real-time operation, `lte-softmodem` and `lte-uesoftmodem`. The latter also now includes an optional channel model, just like oaisim did. +# How to run an eNB with the noS1 option -# [How to build the eNB and the UE](BUILD.md) - -The following paragraph explains how to run the L1 simulator in noS1 mode and using the oai kernel modules. - -# How to run an eNB with the noS1 option +The following paragraph(s) explains how to run the L1 simulator in noS1 mode and using the oai kernel modules. Modify the configuration file for IF4p5 fronthaul, `/openairinterface5g/ci-scripts/conf_files/rcc.band7.nos1.simulator.conf`, and replace the loopback interface with a physical ethernet interface and the IP addresses to work on your network. Copy your modifications to a new file, let's call YYY.conf the resulting configuration file. @@ -42,7 +48,7 @@ $ cd ../ran_build/build $ sudo -E ./lte-softmodem -O YYY.conf --noS1 --nokrnmod 0 ``` -# How to run a UE with the noS1 option +# How to run a UE with the noS1 option Similarly modify the example configuration file in `/openairinterface5g/ci-scripts/conf_files/rru.band7.nos1.simulator.conf` and replace loopback interface and IP addresses. Copy your modifications to a new file, let's call XXX.conf the resulting configuration file. @@ -58,38 +64,17 @@ $ sudo ./lte-uesoftmodem -O XXX.conf -r 25 --siml1 --noS1 --nokrnmod 0 That should give you equivalent functionality to what you had with oaisim including noise and RF channel emulation (path loss / fading, etc.). You should also be able to run multiple UEs. -# Continuous Integration notes -The CI currently tests the noS1 build option with one eNB and one UE in the following scenarios: -* pinging one UE from one eNB -* pinging one eNB from one UE -* iperf download between one eNB and one UE -* iperf upload between one eNB and one UE -* all the above tests are done in FDD 5Mhz mode. - -# How to ping an eNB from a UE and vice versa (with the noS1 option) +# How to ping an eNB from a UE and vice versa (with the noS1 option) Once your eNB and UE (built with the noS1 option) are running and synchronised, you can ping the eNB from the UE with the following command: ```bash ping -I oai0 -c 20 $eNB_ip_addr ``` -where $eNB_ip_addr is the IP address of your eNB. +where `$eNB_ip_addr` is the IP address of your eNB. Similarly, you can ping the UE from the eNB. -The IP adresses of the eNB and the UE are set up by the init_nas_nos1 program and should have the following values: -* eNB_ip_addr set to 20 10.0.1.1 -* ue_ip_addr set to 20 10.0.1.2 - - - - - - - -[oai wiki home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home) - -[oai softmodem features](FEATURE_SET.md) - -[oai softmodem build procedure](BUILD.md) - +The IP adresses of the eNB and the UE are set up by the `init_nas_nos1` program and should have the following values: +* `$eNB_ip_addr` set to 10.0.1.1 +* `ue_ip_addr` set to 10.0.1.2 diff --git a/doc/RUNMODEM.md b/doc/RUNMODEM.md index 6339d7fb5f..e3790114a3 100644 --- a/doc/RUNMODEM.md +++ b/doc/RUNMODEM.md @@ -7,12 +7,18 @@ - Running OAI Softmodems + Running OAI 5G Softmodems -After you have [built the softmodem executables](BUILD.md) you can set your default directory to the build directory `cmake_targets/ran_build/build/` and start testing some use cases. Below, the description of the different oai functionalities should help you choose the oai configuration that suits your need. +This document explains some options for running 5G executables. + +After you have [built the softmodem executables](BUILD.md) you can set your +default directory to the build directory `cmake_targets/ran_build/build/` and +start testing some use cases. Below, the description of the different OAI +functionalities should help you choose the OAI configuration that suits your +need. [[_TOC_]] @@ -20,28 +26,27 @@ After you have [built the softmodem executables](BUILD.md) you can set your defa ## RFsimulator -The RF simulator is an OAI device replacing the radio heads (for example the USRP device). It allows connecting the oai UE (LTE or 5G) and respectively the oai eNodeB or gNodeB through a network interface carrying the time-domain samples, getting rid of over the air unpredictable perturbations. This is the ideal tool to check signal processing algorithms and protocols implementation. The rf simulator has some preliminary support for channel modeling. +The RFsimulator is an OAI device replacing the radio heads (for example the +USRP device). It allows connecting the oai UE (LTE or 5G) and respectively the +oai eNodeB or gNodeB through a network interface carrying the time-domain +samples, getting rid of over the air unpredictable perturbations. This is the +ideal tool to check signal processing algorithms and protocols implementation. +The RFsimulator has some preliminary support for channel modeling. It is planned to enhance this simulator with the following functionalities: - Support for multiple eNodeB's or gNodeB's for hand-over tests -This is an easy use-case to setup and test, as no specific hardware is required. The [rfsimulator page](../radio/rfsimulator/README.md ) contains the detailed documentation. +This is an easy use-case to setup and test, as no specific hardware is required. The [rfsimulator page](../radio/rfsimulator/README.md) contains the detailed documentation. ## L2 nFAPI Simulator -This simulator connects a eNodeB and UEs through a nfapi interface, short-cutting the L1 layer. The objective of this simulator is to allow multi UEs simulation, with a large number of UEs (ideally up to 255 ) .Here to ease the platform setup, UEs are simulated via a single `lte-uesoftmodem` instance. Today the CI tests just with one UE and architecture has to be reviewed to allow a number of UE above about 16. This work is on-going. +This simulator connects an eNodeB and UEs through an nFAPI interface, +short-cutting the L1 layer. The objective of this simulator is to allow multi +UEs simulation, with a large number of UEs (ideally up to 255). -As for the rf simulator, no specific hardware is required. The [L2 nfapi simulator page](L2NFAPI.md) contains the detailed documentation. - -## L1 Simulator - -**This information might be outdated. We recommend to use the RFsimulator as -shown above.** - -The L1 simulator is using the ethernet fronthaul protocol, as used to connect a RRU and a RAU to connect UEs and a eNodeB. UEs are simulated in a single `lte-uesoftmodem` process, as for the nfapi simulator. - -The [L1 simulator page](L1SIM.md) contains the detailed documentation. +As for the RFsimulator, no specific hardware is required. The [L2 nfapi +simulator page](./L2NFAPI.md) contains the detailed documentation. # Running with a true radio head @@ -89,7 +94,7 @@ At the UE the --sa flag will: 4) 5G-NR RRC Reconfiguration 5) Start Downlink and Uplink Data Transfer -Command line parameters for UE in --sa mode: +Command line parameters for UE in `--sa` mode: - `-C` : downlink carrier frequency in Hz (default value 0) - `--CO` : uplink frequency offset for FDD in Hz (default value 0) - `--numerology` : numerology index (default value 1) @@ -104,7 +109,7 @@ sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band sudo ./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --ssb 516 --sa ``` -With the RF simulator (on the same machine): +With the RFsimulator (on the same machine): ```bash sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --gNBs.[0].min_rxtxtime 6 --rfsim --sa @@ -117,11 +122,15 @@ Additionally, at UE side `--uecap_file` option can be used to pass the UE Capabi Some other useful paramters of the UE are - - --ue-fo-compensation: enables the frequency offset compenstation at the UE. This is useful when running over the air and/or without an external clock/time source - - --usrp-args: this is the equivalend paramter of sdr_addrs field in the gNB config file and can be used to identify the USRP and set some basic paramters (like the clock source) - - --clock-source: sets the clock-source (internal or external). - - --time-source: sets the time-source (internal or external). +- `--ue-fo-compensation`: enables the frequency offset compenstation at the UE. This is useful when running over the air and/or without an external clock/time source +- `--usrp-args`: this is the equivalend paramter of `sdr_addrs` field in the gNB config file and can be used to identify the USRP and set some basic paramters (like the clock source) +- `--clock-source`: sets the clock-source (internal or external). +- `--time-source`: sets the time-source (internal or external). +You can see all options by typing +``` +./nr-uesoftmodem --help +``` # Specific OAI modes @@ -154,9 +163,31 @@ In phy-test mode it is possible to mimic the reception of UE Capabilities at gNB ## noS1 setup with OAI UE -Instead of randomly generated payload, in the phy-test mode we can also inject/receive user-plane traffic over a TUN interface. This is the so-called noS1 mode. +Instead of randomly generated payload, in the phy-test mode we can also +inject/receive user-plane traffic over a TUN interface. This is the so-called +noS1 mode. -This setup is described in the [rfsimulator page](../radio/rfsimulator/README.md#5g-case). In theory this should also work with the real hardware target although this has yet to be tested. +The noS1 mode is applicable to both gNB/UE, and enabled by passing `--noS1` as +an option. The gNB/UE will open a TUN interface which the interface names and +IP addresses `oaitun_enb1`/10.0.1.1, and `oaitun_ue1`/10.0.1.2, respectively. +You can then use these interfaces to send traffic, e.g., +```bash +iperf -sui1 -B 10.0.1.2 +``` +to open an iperf server on the UE side, and +```bash +iperf -uc 10.0.1.2 -B 10.0.1.1 -i1 -t10 -b1M +``` +to send data from the gNB down to the UE. + +Note that this does not work if both interfaces are on the same host. We +recommend to use two different hosts, or at least network namespaces, to route +traffic through the gNB/UE tunnel. + +This option is only really helpful for phy-test/do-ra (see below) modes, in +which the UE does not connect to a core network. If the UE connects to a core +network, it receives an IP address for which it automatically opens a network +interface. ## do-ra setup with OAI @@ -244,7 +275,3 @@ The DL logical antenna port configuration can be selected through configuration Finally the number of TX physical antenna in the RU part of the configuration file, `nb_tx`, should be equal or larger than the total number of PDSCH logical antenna ports. [Example of configuration file with parameters for 2-layer MIMO](https://gitlab.eurecom.fr/oai/openairinterface5g/-/blob/develop/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.fr1.273PRB.2x2.usrpn300.conf) - -# Additional links - -[Selecting an alternative ldpc implementation at run time](../openair1/PHY/CODING/DOC/LDPCImplementation.md) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h index 0ff60d4d4f..20c1e890bc 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h @@ -286,7 +286,6 @@ typedef enum { typedef enum { NFAPI_NR_CSET_CONFIG_MIB_SIB1=0, NFAPI_NR_CSET_CONFIG_PDCCH_CONFIG, // implicit assumption of coreset Id other than 0 - NFAPI_NR_CSET_CONFIG_PDCCH_CONFIG_CSET_0 } nfapi_nr_coreset_config_type_e; typedef enum { diff --git a/openair1/PHY/CODING/TESTBENCH/smallblocktest.c b/openair1/PHY/CODING/TESTBENCH/smallblocktest.c index 84825747ec..36e71b2a32 100644 --- a/openair1/PHY/CODING/TESTBENCH/smallblocktest.c +++ b/openair1/PHY/CODING/TESTBENCH/smallblocktest.c @@ -8,144 +8,152 @@ configmodule_interface_t *uniqCfg = NULL; int main(int argc, char *argv[]) { - time_stats_t timeEncoder,timeDecoder; - opp_enabled=1; - reset_meas(&timeEncoder); - reset_meas(&timeDecoder); - randominit(0); + time_stats_t timeEncoder, timeDecoder; + opp_enabled = 1; + reset_meas(&timeEncoder); + reset_meas(&timeDecoder); + randominit(0); - int arguments, iterations = 1000, messageLength = 11; - //int matlabDebug = 0; - uint32_t testInput, encoderOutput, codingDifference, nBitError=0, blockErrorState = 0, blockErrorCumulative=0, bitErrorCumulative=0; - uint16_t estimatedOutput; - double SNRstart = -20.0, SNRstop = 5.0, SNRinc= 0.5; //dB - double SNR, SNR_lin, sigma; - double modulatedInput[NR_SMALL_BLOCK_CODED_BITS], channelOutput[NR_SMALL_BLOCK_CODED_BITS]; - //int16_t channelOutput_int16[NR_SMALL_BLOCK_CODED_BITS]; - int8_t channelOutput_int8[NR_SMALL_BLOCK_CODED_BITS]; - unsigned char qbits=8; + int arguments, iterations = 1000, messageLength = 11; + // int matlabDebug = 0; + uint32_t testInput, encoderOutput, codingDifference, nBitError = 0, blockErrorState = 0, blockErrorCumulative = 0, + bitErrorCumulative = 0; + uint16_t estimatedOutput; + double SNRstart = -20.0, SNRstop = 5.0, SNRinc = 0.5; // dB + double SNR, SNR_lin, sigma; + double modulatedInput[NR_SMALL_BLOCK_CODED_BITS], channelOutput[NR_SMALL_BLOCK_CODED_BITS]; + // int16_t channelOutput_int16[NR_SMALL_BLOCK_CODED_BITS]; + int8_t channelOutput_int8[NR_SMALL_BLOCK_CODED_BITS]; + unsigned char qbits = 8; - while ((arguments = getopt (argc, argv, "s:d:f:l:i:mhg")) != -1) - switch (arguments) - { - case 's': - SNRstart = atof(optarg); - break; + while ((arguments = getopt(argc, argv, "s:d:f:l:i:mhg")) != -1) + switch (arguments) { + case 's': + SNRstart = atof(optarg); + break; - case 'd': - SNRinc = atof(optarg); - break; + case 'd': + SNRinc = atof(optarg); + break; - case 'f': - SNRstop = atof(optarg); - break; + case 'f': + SNRstop = atof(optarg); + break; - case 'l': - messageLength = atoi(optarg); - break; + case 'l': + messageLength = atoi(optarg); + break; - case 'i': - iterations = atoi(optarg); - break; + case 'i': + iterations = atoi(optarg); + break; - /*case 'm': - matlabDebug = 1; - //#define DEBUG_POLAR_MATLAB - break;*/ + /*case 'm': + matlabDebug = 1; + //#define DEBUG_POLAR_MATLAB + break;*/ - case 'g': - iterations = 1; - SNRstart = -6.0; - SNRstop = -6.0; - messageLength = 11; - break; + case 'g': + iterations = 1; + SNRstart = -6.0; + SNRstop = -6.0; + messageLength = 11; + break; - case 'h': - //printf("./smallblocktest -s SNRstart -d SNRinc -f SNRstop -l messageLength -i iterations -m Matlab Debug\n"); - printf("./smallblocktest -s SNRstart -d SNRinc -f SNRstop -l messageLength -i iterations\n"); - exit(-1); + case 'h': + // printf("./smallblocktest -s SNRstart -d SNRinc -f SNRstop -l messageLength -i iterations -m Matlab Debug\n"); + printf("./smallblocktest -s SNRstart -d SNRinc -f SNRstop -l messageLength -i iterations\n"); + exit(-1); - default: - perror("[smallblocktest.c] Problem at argument parsing with getopt"); - exit(-1); - } + default: + perror("[smallblocktest.c] Problem at argument parsing with getopt"); + exit(-1); + } + uint16_t mask = 0x07ff >> (11 - messageLength); + for (SNR = SNRstart; SNR <= SNRstop; SNR += SNRinc) { + printf("SNR %f\n", SNR); + SNR_lin = pow(10, SNR / 10.0); + sigma = 1.0 / sqrt(SNR_lin); - uint16_t mask = 0x07ff >> (11-messageLength); - for (SNR = SNRstart; SNR <= SNRstop; SNR += SNRinc) { - printf("SNR %f\n",SNR); - SNR_lin = pow(10, SNR/10.0); - sigma = 1.0/sqrt(SNR_lin); + for (int itr = 1; itr <= iterations; itr++) { + // Generate random test input of length "messageLength" + testInput = 0; + for (int i = 1; i < messageLength; i++) { + testInput |= (((uint32_t)(rand() % 2)) & 1); + testInput <<= 1; + } + testInput |= (((uint32_t)(rand() % 2)) & 1); + // Encoding + start_meas(&timeEncoder); + encoderOutput = encodeSmallBlock(testInput, messageLength); + stop_meas(&timeEncoder); - for (int itr = 1; itr <= iterations; itr++) { + for (int i = 0; i < NR_SMALL_BLOCK_CODED_BITS; i++) { + // BPSK modulation + if ((encoderOutput >> i) & 1) { + modulatedInput[i] = -1; + } else { + modulatedInput[i] = 1; + } - //Generate random test input of length "messageLength" - testInput = 0; - for (int i = 1; i < messageLength; i++) { - testInput |= ( ((uint32_t) (rand()%2)) &1); - testInput<<=1; - } - testInput |= ( ((uint32_t) (rand()%2)) &1); - //Encoding - start_meas(&timeEncoder); - encoderOutput = encodeSmallBlock((uint16_t*)&testInput, (uint8_t)messageLength); - stop_meas(&timeEncoder); + // AWGN + channelOutput[i] = modulatedInput[i] + (gaussdouble(0.0, 1.0) * (1 / sqrt(SNR_lin))); - for (int i=0; i>i) & 1 ) { - modulatedInput[i]=-1; - } else { - modulatedInput[i]=1; - } + // Quantization + channelOutput_int8[i] = quantize(sigma / 16.0, channelOutput[i], qbits); + } - //AWGN - channelOutput[i] = modulatedInput[i] + ( gaussdouble(0.0,1.0) * ( 1/sqrt(SNR_lin) ) ); - - //Quantization - channelOutput_int8[i] = quantize(sigma/16.0, channelOutput[i], qbits); - } - - //Decoding - start_meas(&timeDecoder); - estimatedOutput = decodeSmallBlock(channelOutput_int8, (uint8_t)messageLength); - stop_meas(&timeDecoder); + // Decoding + start_meas(&timeDecoder); + estimatedOutput = decodeSmallBlock(channelOutput_int8, (uint8_t)messageLength); + stop_meas(&timeDecoder); #ifdef DEBUG_SMALLBLOCKTEST - printf("[smallblocktest] Input = 0x%x, Output = 0x%x, DecoderOutput = 0x%x\n", testInput, encoderOutput, estimatedOutput); - for (int i=0;i<32;i++) - printf("[smallblocktest] Input[%d] = %d, Output[%d] = %d, codingDifference[%d]=%d, Mask[%d] = %d\n", i, (testInput>>i)&1, i, (estimatedOutput>>i)&1, i, (codingDifference>>i)&1, i, (mask>>i)&1); + printf("[smallblocktest] Input = 0x%x, Output = 0x%x, DecoderOutput = 0x%x\n", testInput, encoderOutput, estimatedOutput); + for (int i = 0; i < 32; i++) + printf("[smallblocktest] Input[%d] = %d, Output[%d] = %d, codingDifference[%d]=%d, Mask[%d] = %d\n", + i, + (testInput >> i) & 1, + i, + (estimatedOutput >> i) & 1, + i, + (codingDifference >> i) & 1, + i, + (mask >> i) & 1); #endif - //Error Calculation - estimatedOutput &= mask; - codingDifference = ((uint32_t)estimatedOutput) ^ testInput; // Count the # of 1's in codingDifference by Brian Kernighan’s algorithm. + // Error Calculation + estimatedOutput &= mask; + codingDifference = + ((uint32_t)estimatedOutput) ^ testInput; // Count the # of 1's in codingDifference by Brian Kernighan’s algorithm. - for (nBitError = 0; codingDifference; nBitError++) - codingDifference &= codingDifference - 1; + for (nBitError = 0; codingDifference; nBitError++) + codingDifference &= codingDifference - 1; - blockErrorState = (nBitError > 0) ? 1 : 0; + blockErrorState = (nBitError > 0) ? 1 : 0; - blockErrorCumulative+=blockErrorState; - bitErrorCumulative+=nBitError; + blockErrorCumulative += blockErrorState; + bitErrorCumulative += nBitError; - nBitError = 0; blockErrorState = 0; - } + nBitError = 0; + blockErrorState = 0; + } - //Error statistics for the SNR; iteration times are in nanoseconds and microseconds, respectively. - printf("[smallblocktest] SNR=%+7.3f, BER=%9.6f, BLER=%9.6f, t_Encoder=%9.3fns, t_Decoder=%7.3fus\n", - SNR, - ((double)bitErrorCumulative / (iterations*messageLength)), - ((double)blockErrorCumulative/iterations), - ((double)timeEncoder.diff/timeEncoder.trials)/(get_cpu_freq_GHz()), - ((double)timeDecoder.diff/timeDecoder.trials)/(get_cpu_freq_GHz()*1000.0)); + // Error statistics for the SNR; iteration times are in nanoseconds and microseconds, respectively. + printf("[smallblocktest] SNR=%+7.3f, BER=%9.6f, BLER=%9.6f, t_Encoder=%9.3fns, t_Decoder=%7.3fus\n", + SNR, + ((double)bitErrorCumulative / (iterations * messageLength)), + ((double)blockErrorCumulative / iterations), + ((double)timeEncoder.diff / timeEncoder.trials) / (get_cpu_freq_GHz()), + ((double)timeDecoder.diff / timeDecoder.trials) / (get_cpu_freq_GHz() * 1000.0)); - blockErrorCumulative=0; - bitErrorCumulative=0; - } + blockErrorCumulative = 0; + bitErrorCumulative = 0; + } - print_meas(&timeEncoder, "smallblock_encoder", NULL, NULL); - print_meas(&timeDecoder, "smallblock_decoder", NULL, NULL); + print_meas(&timeEncoder, "smallblock_encoder", NULL, NULL); + print_meas(&timeDecoder, "smallblock_decoder", NULL, NULL); - return (0); + return (0); } diff --git a/openair1/PHY/CODING/nrSmallBlock/encodeSmallBlock.c b/openair1/PHY/CODING/nrSmallBlock/encodeSmallBlock.c index 8358bd270b..3078243c8f 100644 --- a/openair1/PHY/CODING/nrSmallBlock/encodeSmallBlock.c +++ b/openair1/PHY/CODING/nrSmallBlock/encodeSmallBlock.c @@ -34,11 +34,12 @@ //input = [0 ... 0 c_K-1 ... c_2 c_1 c_0] //output = [d_31 d_30 ... d_2 d_1 d_0] -uint32_t encodeSmallBlock(uint16_t *in, uint8_t len){ - uint32_t out = 0; - for (uint16_t i=0; i 0) - out^=nrSmallBlockBasis[i]; +uint32_t encodeSmallBlock(int in, int len) +{ + uint32_t out = 0; + for (int i = 0; i < len; i++) + if ((in & (1 << i)) > 0) + out ^= nrSmallBlockBasis[i]; - return out; + return out; } diff --git a/openair1/PHY/CODING/nrSmallBlock/nr_small_block_defs.h b/openair1/PHY/CODING/nrSmallBlock/nr_small_block_defs.h index 50559aa0d2..7c8554f807 100644 --- a/openair1/PHY/CODING/nrSmallBlock/nr_small_block_defs.h +++ b/openair1/PHY/CODING/nrSmallBlock/nr_small_block_defs.h @@ -43,7 +43,7 @@ #define L1d_CLS 64 -uint32_t encodeSmallBlock(uint16_t *in, uint8_t len); +uint32_t encodeSmallBlock(int in, int len); uint16_t decodeSmallBlock(int8_t *in, uint8_t len); diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_common_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_common_proto.h index 6890e52553..79b3daa212 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_common_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_common_proto.h @@ -42,7 +42,7 @@ void nr_group_sequence_hopping(pucch_GroupHopping_t PUCCH_GroupHopping, uint32_t n_id, - uint8_t n_hop, + int n_hop, int nr_slot_tx, uint8_t *u, uint8_t *v); diff --git a/openair1/PHY/NR_TRANSPORT/nr_uci_tools_common.c b/openair1/PHY/NR_TRANSPORT/nr_uci_tools_common.c index cccdaed8ef..1c3d0f7008 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_uci_tools_common.c +++ b/openair1/PHY/NR_TRANSPORT/nr_uci_tools_common.c @@ -32,12 +32,13 @@ #include "nr_dci.h" -void nr_group_sequence_hopping (pucch_GroupHopping_t PUCCH_GroupHopping, - uint32_t n_id, - uint8_t n_hop, - int nr_slot_tx, - uint8_t *u, - uint8_t *v) { +void nr_group_sequence_hopping(pucch_GroupHopping_t PUCCH_GroupHopping, + uint32_t n_id, + int n_hop, + int nr_slot_tx, + uint8_t *u, + uint8_t *v) +{ /* * Implements TS 38.211 subclause 6.3.2.2.1 Group and sequence hopping * The following variables are set by higher layers: diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index 84232ea140..e878a3c0bb 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -158,8 +158,9 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, int soffset = (slot & 3) * frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size; AssertFatal(pucch_pdu->bit_len_harq > 0 || pucch_pdu->sr_flag > 0, - "Either bit_len_harq (%d) or sr_flag (%d) must be > 0\n", - pucch_pdu->bit_len_harq,pucch_pdu->sr_flag); + "Either bit_len_harq (%d) or sr_flag (%d) must be > 0\n", + pucch_pdu->bit_len_harq, + pucch_pdu->sr_flag); NR_gNB_PHY_STATS_t *phy_stats = get_phy_stats(gNB, pucch_pdu->rnti); AssertFatal(phy_stats != NULL, "phy_stats shouldn't be NULL\n"); @@ -188,43 +189,19 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, int cs_ind = get_pucch0_cs_lut_index(gNB,pucch_pdu); /* * Implement TS 38.211 Subclause 6.3.2.3.1 Sequence generation - * - */ - /* * Defining cyclic shift hopping TS 38.211 Subclause 6.3.2.2.2 - */ - // alpha is cyclic shift - //double alpha; - // lnormal is the OFDM symbol number in the PUCCH transmission where l=0 corresponds to the first OFDM symbol of the PUCCH transmission - //uint8_t lnormal; - // lprime is the index of the OFDM symbol in the slot that corresponds to the first OFDM symbol of the PUCCH transmission in the slot given by [5, TS 38.213] - //uint8_t lprime; - - /* * in TS 38.213 Subclause 9.2.1 it is said that: * for PUCCH format 0 or PUCCH format 1, the index of the cyclic shift * is indicated by higher layer parameter PUCCH-F0-F1-initial-cyclic-shift */ - - /* - * Implementing TS 38.211 Subclause 6.3.2.3.1, the sequence x(n) shall be generated according to: - * x(l*12+n) = r_u_v_alpha_delta(n) - */ - // the value of u,v (delta always 0 for PUCCH) has to be calculated according to TS 38.211 Subclause 6.3.2.2.1 - uint8_t u[2]={0},v[2]={0}; - - // x_n contains the sequence r_u_v_alpha_delta(n) - - int n,i; int prb_offset[2] = {pucch_pdu->bwp_start+pucch_pdu->prb_start, pucch_pdu->bwp_start+pucch_pdu->prb_start}; pucch_GroupHopping_t pucch_GroupHopping = pucch_pdu->group_hop_flag + (pucch_pdu->sequence_hop_flag << 1); - nr_group_sequence_hopping(pucch_GroupHopping, - pucch_pdu->hopping_id, - 0, - slot, - &u[0], - &v[0]); // calculating u and v value first hop + // the value of u,v (delta always 0 for PUCCH) has to be calculated according + // to TS 38.211 Subclause 6.3.2.2.1 + uint8_t u[2] = {0}, v[2] = {0}; + nr_group_sequence_hopping(pucch_GroupHopping, pucch_pdu->hopping_id, 0, slot, u, + v); // calculating u and v value first hop LOG_D(PHY,"pucch0: u %d, v %d\n",u[0],v[0]); if (pucch_pdu->freq_hop_flag == 1) { @@ -253,10 +230,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uint8_t index=0; int nb_re_pucch = 12*pucch_pdu->prb_size; // prb size is 1 - int32_t rp[frame_parms->nb_antennas_rx][pucch_pdu->nr_of_symbols][nb_re_pucch]; - memset(rp, 0, sizeof(rp)); - int32_t *tmp_rp = NULL; - int signal_energy = 0; + int signal_energy = 0, signal_energy_ant0 = 0; for (int l=0; lnr_of_symbols; l++) { uint8_t l2 = l + pucch_pdu->start_symbol_index; @@ -266,39 +240,38 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, re_offset[l]-=frame_parms->ofdm_symbol_size; for (int aa=0;aanb_antennas_rx;aa++) { - tmp_rp = (int32_t *)&rxdataF[aa][soffset + l2*frame_parms->ofdm_symbol_size]; + c16_t rp[nb_re_pucch]; + memset(rp, 0, sizeof(rp)); + c16_t *tmp_rp = &rxdataF[aa][soffset + l2 * frame_parms->ofdm_symbol_size]; if(re_offset[l] + nb_re_pucch > frame_parms->ofdm_symbol_size) { int neg_length = frame_parms->ofdm_symbol_size-re_offset[l]; int pos_length = nb_re_pucch-neg_length; - memcpy((void*)rp[aa][l],(void*)&tmp_rp[re_offset[l]],neg_length*sizeof(int32_t)); - memcpy((void*)&rp[aa][l][neg_length],(void*)tmp_rp,pos_length*sizeof(int32_t)); + memcpy(rp, &tmp_rp[re_offset[l]], neg_length * sizeof(*tmp_rp)); + memcpy(&rp[neg_length], tmp_rp, pos_length * sizeof(*tmp_rp)); } else - memcpy((void*)rp[aa][l],(void*)&tmp_rp[re_offset[l]],nb_re_pucch*sizeof(int32_t)); + memcpy(rp, &tmp_rp[re_offset[l]], nb_re_pucch * sizeof(*tmp_rp)); - c16_t *r = (c16_t*)&rp[aa][l]; - - for (n=0;nnr_of_symbols * frame_parms->nb_antennas_rx); int pucch_power_dBtimes10 = 10 * dB_fixed(signal_energy); //int32_t no_corr = 0; int seq_index = 0; - int64_t temp; - for(i=0;inb_antennas_rx][2]; for (int aa=0;aanb_antennas_rx;aa++) { for (int l=0;lnr_of_symbols;l++) { @@ -309,7 +282,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, printf("PUCCH symbol %d seq %d, seq_index %d, mcs %d\n",l,i,seq_index,mcs[i]); #endif corr[aa][l]=(c64_t){0}; - for (n = 0; n < 12; n++) { + for (int n = 0; n < 12; n++) { corr[aa][l].r += xr[aa][l][n].r * idft12_re[seq_index][n] + xr[aa][l][n].i * idft12_im[seq_index][n]; corr[aa][l].i += xr[aa][l][n].r * idft12_im[seq_index][n] - xr[aa][l][n].i * idft12_re[seq_index][n]; } @@ -321,30 +294,32 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, mcs[i],seq_index,corr[0][0].r,corr[0][0].i, 10*log10((double)squaredMod(corr[0][0]))); if (pucch_pdu->nr_of_symbols==2) - LOG_D(PHY,"PUCCH 2nd symbol IDFT[%d/%d] = (%ld,%ld)=>%f\n", - mcs[i],seq_index,corr[0][1].r,corr[0][1].i, - 10*log10((double)squaredMod(corr[0][1]))); + LOG_D(PHY, + "PUCCH 2nd symbol IDFT[%d/%d] = (%ld,%ld)=>%f\n", + mcs[i], + seq_index, + corr[0][1].r, + corr[0][1].i, + 10 * log10((double)squaredMod(corr[0][1]))); + int64_t temp = 0; if (pucch_pdu->freq_hop_flag == 0) { - if (pucch_pdu->nr_of_symbols==1) {// non-coherent correlation - temp=0; - for (int aa=0;aanb_antennas_rx;aa++) - temp+=squaredMod(corr[aa][0]); - } else { - temp=0; - for (int aa=0;aanb_antennas_rx;aa++) { - c64_t corr2; - csum(corr2, corr[aa][0], corr[aa][1]); - // coherent combining of 2 symbols and then complex modulus for single-frequency case - temp+=corr2.r*corr2.r + corr2.i*corr2.i; - } + if (pucch_pdu->nr_of_symbols == 1) { // non-coherent correlation + for (int aa = 0; aa < frame_parms->nb_antennas_rx; aa++) + temp += squaredMod(corr[aa][0]); + } else { + for (int aa = 0; aa < frame_parms->nb_antennas_rx; aa++) { + c64_t corr2; + csum(corr2, corr[aa][0], corr[aa][1]); + // coherent combining of 2 symbols and then complex modulus for + // single-frequency case + temp += corr2.r * corr2.r + corr2.i * corr2.i; } - } else if (pucch_pdu->freq_hop_flag == 1) { + } + } else { // full non-coherent combining of 2 symbols for frequency-hopping case - temp=0; - for (int aa=0;aanb_antennas_rx;aa++) + for (int aa = 0; aa < frame_parms->nb_antennas_rx; aa++) temp += squaredMod(corr[aa][0]) + squaredMod(corr[aa][1]); } - else AssertFatal(1==0,"shouldn't happen\n"); if (temp>xrtmag) { xrtmag_next = xrtmag; @@ -356,11 +331,11 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, for (int aa=0;aanb_antennas_rx;aa++) { temp2 += squaredMod(corr[aa][0]); if (pucch_pdu->nr_of_symbols==2) - temp3 += squaredMod(corr[aa][1]); + temp3 += squaredMod(corr[aa][1]); } uci_stats->current_pucch0_stat0= dB_fixed64(temp2); if ( pucch_pdu->nr_of_symbols==2) - uci_stats->current_pucch0_stat1= dB_fixed64(temp3); + uci_stats->current_pucch0_stat1 = dB_fixed64(temp3); } else if (temp>xrtmag_next) xrtmag_next = temp; @@ -377,28 +352,30 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_stats->pucch0_n01 = gNB->measurements.n0_subband_power_tot_dB[prb_offset[1]]; LOG_D(PHY,"n00[%d] = %d, n01[%d] = %d\n",prb_offset[0],uci_stats->pucch0_n00,prb_offset[1],uci_stats->pucch0_n01); // estimate CQI for MAC (from antenna port 0 only) - int max_n0 = max(gNB->measurements.n0_subband_power_tot_dB[prb_offset[0]], - gNB->measurements.n0_subband_power_tot_dB[prb_offset[1]]); - int SNRtimes10,sigenergy=0; - for (int aa=0;aanb_antennas_rx;aa++) - sigenergy += signal_energy_nodc(rp[aa][0],12); - SNRtimes10 = pucch_power_dBtimes10 - (10 * max_n0); + int max_n0 = + max(gNB->measurements.n0_subband_power_tot_dB[prb_offset[0]], gNB->measurements.n0_subband_power_tot_dB[prb_offset[1]]); + const int SNRtimes10 = pucch_power_dBtimes10 - (10 * max_n0); int cqi; - if (SNRtimes10 < -640) cqi=0; - else if (SNRtimes10 > 635) cqi=255; - else cqi=(640+SNRtimes10)/5; + if (SNRtimes10 < -640) + cqi = 0; + else if (SNRtimes10 > 635) + cqi = 255; + else + cqi = (640 + SNRtimes10) / 5; uci_stats->pucch0_thres = gNB->pucch0_thres; /* + (10*max_n0);*/ bool no_conf=false; if (nr_sequences>1) { if (/*xrtmag_dBtimes10 < (30+xrtmag_next_dBtimes10) ||*/ SNRtimes10 < gNB->pucch0_thres) { no_conf=true; - LOG_D(PHY,"%d.%d PUCCH bad confidence: %d threshold, %d, %d, %d\n", - frame, slot, - uci_stats->pucch0_thres, - SNRtimes10, - xrtmag_dBtimes10, - xrtmag_next_dBtimes10); + LOG_D(PHY, + "%d.%d PUCCH bad confidence: %d threshold, %d, %d, %d\n", + frame, + slot, + uci_stats->pucch0_thres, + SNRtimes10, + xrtmag_dBtimes10, + xrtmag_next_dBtimes10); } } gNB->bad_pucch += no_conf; @@ -408,7 +385,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_pdu->rnti = pucch_pdu->rnti; uci_pdu->ul_cqi = cqi; uci_pdu->timing_advance = 0xffff; // currently not valid - uci_pdu->rssi = 1280 - (10*dB_fixed(32767*32767))-dB_fixed_times10(sigenergy); + uci_pdu->rssi = 1280 - (10 * dB_fixed(32767 * 32767)) - dB_fixed_times10(signal_energy_ant0); if (pucch_pdu->bit_len_harq==0) { uci_pdu->sr.sr_confidence_level = SNRtimes10 < uci_stats->pucch0_thres; @@ -426,7 +403,9 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_pdu->harq.harq_confidence_level = no_conf; uci_pdu->harq.harq_list[0].harq_value = !(index&0x01); LOG_D(PHY, - "[DLSCH/PDSCH/PUCCH] %d.%d HARQ %s with confidence level %s xrt_mag %d xrt_mag_next %d pucch_power_dBtimes10 %d n0 %d (%d,%d) pucch0_thres %d, " + "[DLSCH/PDSCH/PUCCH] %d.%d HARQ %s with confidence level %s xrt_mag " + "%d xrt_mag_next %d pucch_power_dBtimes10 %d n0 %d " + "(%d,%d) pucch0_thres %d, " "cqi %d, SNRtimes10 %d, energy %f\n", frame, slot, @@ -441,7 +420,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uci_stats->pucch0_thres, cqi, SNRtimes10, - 10 * log10((double)sigenergy)); + 10 * log10((double)signal_energy_ant0)); if (pucch_pdu->sr_flag == 1) { uci_pdu->sr.sr_indication = (index>1); @@ -488,10 +467,10 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, } //*****************************************************************// void nr_decode_pucch1(c16_t **rxdataF, - pucch_GroupHopping_t pucch_GroupHopping, - uint32_t n_id, // hoppingID higher layer parameter + pucch_GroupHopping_t pucch_GroupHopping, + uint32_t n_id, // hoppingID higher layer parameter uint64_t *payload, - NR_DL_FRAME_PARMS *frame_parms, + NR_DL_FRAME_PARMS *frame_parms, int16_t amp, int nr_tti_tx, uint8_t m0, @@ -503,33 +482,33 @@ void nr_decode_pucch1(c16_t **rxdataF, uint8_t nr_bit) { #ifdef DEBUG_NR_PUCCH_RX - printf("\t [nr_generate_pucch1] start function at slot(nr_tti_tx)=%d payload=%lp m0=%d nrofSymbols=%d startingSymbolIndex=%d startingPRB=%d startingPRB_intraSlotHopping=%d timeDomainOCC=%d nr_bit=%d\n", - nr_tti_tx,payload,m0,nrofSymbols,startingSymbolIndex,startingPRB,startingPRB_intraSlotHopping,timeDomainOCC,nr_bit); + printf( + "\t [nr_generate_pucch1] start function at slot(nr_tti_tx)=%d " + "payload=%lux m0=%d nrofSymbols=%d startingSymbolIndex=%d " + "startingPRB=%d startingPRB_intraSlotHopping=%d timeDomainOCC=%d " + "nr_bit=%d\n", + nr_tti_tx, + *payload, + m0, + nrofSymbols, + startingSymbolIndex, + startingPRB, + startingPRB_intraSlotHopping, + timeDomainOCC, + nr_bit); #endif /* * Implement TS 38.211 Subclause 6.3.2.4.1 Sequence modulation * */ - int soffset = (nr_tti_tx&3)*frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size; - // complex-valued symbol d_re, d_im containing complex-valued symbol d(0): - int16_t d_re=0, d_im=0,d1_re=0,d1_im=0; -#ifdef DEBUG_NR_PUCCH_RX - printf("\t [nr_generate_pucch1] sequence modulation: payload=%lp \tde_re=%d \tde_im=%d\n",payload,d_re,d_im); -#endif - /* - * Defining cyclic shift hopping TS 38.211 Subclause 6.3.2.2.2 - */ - // alpha is cyclic shift - double alpha; - // lnormal is the OFDM symbol number in the PUCCH transmission where l=0 corresponds to the first OFDM symbol of the PUCCH transmission - //uint8_t lnormal = 0 ; + const int soffset = (nr_tti_tx & 3) * frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size; // lprime is the index of the OFDM symbol in the slot that corresponds to the first OFDM symbol of the PUCCH transmission in the slot given by [5, TS 38.213] - uint8_t lprime = startingSymbolIndex; + const int lprime = startingSymbolIndex; // mcs = 0 except for PUCCH format 0 - uint8_t mcs=0; + const uint8_t mcs = 0; // r_u_v_alpha_delta_re and r_u_v_alpha_delta_im tables containing the sequence y(n) for the PUCCH, when they are multiplied by d(0) // r_u_v_alpha_delta_dmrs_re and r_u_v_alpha_delta_dmrs_im tables containing the sequence for the DM-RS. - int16_t r_u_v_alpha_delta_re[12],r_u_v_alpha_delta_im[12],r_u_v_alpha_delta_dmrs_re[12],r_u_v_alpha_delta_dmrs_im[12]; + c16_t r_u_v_alpha_delta[12], r_u_v_alpha_delta_dmrs[12]; /* * in TS 38.213 Subclause 9.2.1 it is said that: * for PUCCH format 0 or PUCCH format 1, the index of the cyclic shift @@ -540,21 +519,12 @@ void nr_decode_pucch1(c16_t **rxdataF, */ // the value of u,v (delta always 0 for PUCCH) has to be calculated according to TS 38.211 Subclause 6.3.2.2.1 uint8_t u=0,v=0;//,delta=0; - // if frequency hopping is disabled, intraSlotFrequencyHopping is not provided - // n_hop = 0 - // if frequency hopping is enabled, intraSlotFrequencyHopping is provided - // n_hop = 0 for first hop - // n_hop = 1 for second hop - uint8_t n_hop = 0; + // Intra-slot frequency hopping shall be assumed when the higher-layer parameter intraSlotFrequencyHopping is provided, // regardless of whether the frequency-hop distance is zero or not, // otherwise no intra-slot frequency hopping shall be assumed //uint8_t PUCCH_Frequency_Hopping = 0 ; // from higher layers - uint8_t intraSlotFrequencyHopping = 0; - - if (startingPRB != startingPRB_intraSlotHopping) { - intraSlotFrequencyHopping=1; - } + const bool intraSlotFrequencyHopping = startingPRB != startingPRB_intraSlotHopping; #ifdef DEBUG_NR_PUCCH_RX printf("\t [nr_generate_pucch1] intraSlotFrequencyHopping = %d \n",intraSlotFrequencyHopping); @@ -562,119 +532,110 @@ void nr_decode_pucch1(c16_t **rxdataF, /* * Implementing TS 38.211 Subclause 6.3.2.4.2 Mapping to physical resources */ - //int32_t *txptr; - uint32_t re_offset=0; - int i=0; #define MAX_SIZE_Z 168 // this value has to be calculated from mprime*12*table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_noHop[pucch_symbol_length]+m*12+n - int16_t z_re_rx[MAX_SIZE_Z],z_im_rx[MAX_SIZE_Z],z_re_temp,z_im_temp; - int16_t z_dmrs_re_rx[MAX_SIZE_Z],z_dmrs_im_rx[MAX_SIZE_Z],z_dmrs_re_temp,z_dmrs_im_temp; - memset(z_re_rx,0,MAX_SIZE_Z*sizeof(int16_t)); - memset(z_im_rx,0,MAX_SIZE_Z*sizeof(int16_t)); - memset(z_dmrs_re_rx,0,MAX_SIZE_Z*sizeof(int16_t)); - memset(z_dmrs_im_rx,0,MAX_SIZE_Z*sizeof(int16_t)); - int l=0; - for(l=0;lN_RB_DL >> 1; + const bool nb_rb_is_even = (frame_parms->N_RB_DL & 1) == 0; + for (int l = 0; l < nrofSymbols; l++) { // extracting data and dmrs from rxdataF + if (intraSlotFrequencyHopping && (l < floor(nrofSymbols / 2))) { // intra-slot hopping enabled, we need + // to calculate new offset PRB startingPRB = startingPRB + startingPRB_intraSlotHopping; } + int re_offset = (l + startingSymbolIndex) * frame_parms->ofdm_symbol_size; - if ((startingPRB < (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 0)) { // if number RBs in bandwidth is even and current PRB is lower band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset; - } - - if ((startingPRB >= (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 0)) { // if number RBs in bandwidth is even and current PRB is upper band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*(startingPRB-(frame_parms->N_RB_DL>>1))); - } - - if ((startingPRB < (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd and current PRB is lower band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset; - } - - if ((startingPRB > (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd and current PRB is upper band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*(startingPRB-(frame_parms->N_RB_DL>>1))) + 6; - } - - if ((startingPRB == (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd and current PRB contains DC - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*startingPRB) + frame_parms->first_carrier_offset; + if (nb_rb_is_even) { + if (startingPRB < half_nb_rb_dl) // if number RBs in bandwidth is even and + // current PRB is lower band + re_offset += 12 * startingPRB + frame_parms->first_carrier_offset; + else // if number RBs in bandwidth is even and current PRB is upper band + re_offset += 12 * (startingPRB - half_nb_rb_dl); + } else { + if (startingPRB < half_nb_rb_dl) // if number RBs in bandwidth is odd and + // current PRB is lower band + re_offset += 12 * startingPRB + frame_parms->first_carrier_offset; + else if (startingPRB > half_nb_rb_dl) // if number RBs in bandwidth is odd + // and current PRB is upper band + re_offset += 12 * (startingPRB - half_nb_rb_dl) + 6; + else // if number RBs in bandwidth is odd and current PRB contains DC + re_offset += 12 * startingPRB + frame_parms->first_carrier_offset; } for (int n=0; n<12; n++) { - if ((n==6) && (startingPRB == (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { + const int current_subcarrier = l * 12 + n; + if (n == 6 && startingPRB == half_nb_rb_dl && !nb_rb_is_even) { // if number RBs in bandwidth is odd and current PRB contains DC, we need to recalculate the offset when n=6 (for second half PRB) re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size); } - if (l%2 == 1) { // mapping PUCCH according to TS38.211 subclause 6.4.1.3.1 - z_re_rx[i+n] = ((int16_t *)&rxdataF[0][soffset+re_offset])[0]; - z_im_rx[i+n] = ((int16_t *)&rxdataF[0][soffset+re_offset])[1]; + if (l % 2 == 1) // mapping PUCCH or DM-RS according to TS38.211 subclause 6.4.1.3.1 + z_rx[current_subcarrier] = rxdataF[0][soffset + re_offset]; + else + z_dmrs_rx[current_subcarrier] = rxdataF[0][soffset + re_offset]; #ifdef DEBUG_NR_PUCCH_RX - printf("\t [nr_generate_pucch1] mapping PUCCH to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \tz_pucch[%d]=txptr(%u)=(x_n(l=%d,n=%d)=(%d,%d))\n", - amp,frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,i+n,re_offset, - l,n,((int16_t *)&rxdataF[0][soffset+re_offset])[0],((int16_t *)&rxdataF[0][soffset+re_offset])[1]); + printf( + "\t [nr_generate_pucch1] mapping %s to RE \t amp=%d " + "\tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d " + "\tz_pucch[%d]=txptr(%u)=(x_n(l=%d,n=%d)=(%d,%d))\n", + l % 2 ? "PUCCH" : "DM-RS", + amp, + frame_parms->ofdm_symbol_size, + frame_parms->N_RB_DL, + frame_parms->first_carrier_offset, + current_subcarrier, + re_offset, + l, + n, + rxdataF[0][soffset + re_offset].r, + rxdataF[0][soffset + re_offset].i); #endif - } - - if (l%2 == 0) { // mapping DM-RS signal according to TS38.211 subclause 6.4.1.3.1 - z_dmrs_re_rx[i+n] = ((int16_t *)&rxdataF[0][soffset+re_offset])[0]; - z_dmrs_im_rx[i+n] = ((int16_t *)&rxdataF[0][soffset+re_offset])[1]; - // printf("%d\t%d\t%d\n",l,z_dmrs_re_rx[i+n],z_dmrs_im_rx[i+n]); -#ifdef DEBUG_NR_PUCCH_RX - printf("\t [nr_generate_pucch1] mapping DM-RS to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \tz_dm-rs[%d]=txptr(%u)=(x_n(l=%d,n=%d)=(%d,%d))\n", - amp,frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,i+n,re_offset, - l,n,((int16_t *)&rxdataF[0][soffset+re_offset])[0],((int16_t *)&rxdataF[0][soffset+re_offset])[1]); -#endif - // printf("l=%d\ti=%d\tre_offset=%d\treceived dmrs re=%d\tim=%d\n",l,i,re_offset,z_dmrs_re_rx[i+n],z_dmrs_im_rx[i+n]); - } - re_offset++; } - if (l%2 == 1) i+=12; } - int16_t y_n_re[12],y_n_im[12],y1_n_re[12],y1_n_im[12]; - memset(y_n_re,0,12*sizeof(int16_t)); - memset(y_n_im,0,12*sizeof(int16_t)); - memset(y1_n_re,0,12*sizeof(int16_t)); - memset(y1_n_im,0,12*sizeof(int16_t)); + cd_t y_n[12] = {0}, y1_n[12] = {0}; //generating transmitted sequence and dmrs - for (l=0; l= (int)floor(nrofSymbols/2))) n_hop = 1; // n_hop = 1 for second hop + // if frequency hopping is disabled, intraSlotFrequencyHopping is not + // provided + // n_hop = 0 + // if frequency hopping is enabled, intraSlotFrequencyHopping is provided + // n_hop = 0 for first hop + // n_hop = 1 for second hop + const int n_hop = intraSlotFrequencyHopping && l >= nrofSymbols / 2 ? 1 : 0; #ifdef DEBUG_NR_PUCCH_RX printf("\t [nr_generate_pucch1] entering function nr_group_sequence_hopping with n_hop=%d, nr_tti_tx=%d\n", n_hop,nr_tti_tx); #endif nr_group_sequence_hopping(pucch_GroupHopping,n_id,n_hop,nr_tti_tx,&u,&v); // calculating u and v value - alpha = nr_cyclic_shift_hopping(n_id,m0,mcs,l,lprime,nr_tti_tx); - + // Defining cyclic shift hopping TS 38.211 Subclause 6.3.2.2.2 + double alpha = nr_cyclic_shift_hopping(n_id, m0, mcs, l, lprime, nr_tti_tx); for (int n=0; n<12; n++) { // generating low papr sequences - if(l%2==1){ - r_u_v_alpha_delta_re[n] = (int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15) - - (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15))); // Re part of base sequence shifted by alpha - r_u_v_alpha_delta_im[n] = (int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15) - + (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15))); // Im part of base sequence shifted by alpha - } - else{ - r_u_v_alpha_delta_dmrs_re[n] = (int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15) - - (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15))); // Re part of DMRS base sequence shifted by alpha - r_u_v_alpha_delta_dmrs_im[n] = (int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15) - + (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15))); // Im part of DMRS base sequence shifted by alpha - r_u_v_alpha_delta_dmrs_re[n] = (int16_t)(((int32_t)(amp*r_u_v_alpha_delta_dmrs_re[n]))>>15); - r_u_v_alpha_delta_dmrs_im[n] = (int16_t)(((int32_t)(amp*r_u_v_alpha_delta_dmrs_im[n]))>>15); - } - // printf("symbol=%d\tr_u_rx_re=%d\tr_u_rx_im=%d\n",l,r_u_v_alpha_delta_dmrs_re[n], r_u_v_alpha_delta_dmrs_im[n]); - // PUCCH sequence = DM-RS sequence multiplied by d(0) - /* y_n_re[n] = (int16_t)(((((int32_t)(r_u_v_alpha_delta_re[n])*d_re)>>15) - - (((int32_t)(r_u_v_alpha_delta_im[n])*d_im)>>15))); // Re part of y(n) - y_n_im[n] = (int16_t)(((((int32_t)(r_u_v_alpha_delta_re[n])*d_im)>>15) - + (((int32_t)(r_u_v_alpha_delta_im[n])*d_re)>>15))); // Im part of y(n) */ + const c16_t angle = {lround(32767 * cos(alpha * n)), lround(32767 * sin(alpha * n))}; + const c16_t table = {table_5_2_2_2_2_Re[u][n], table_5_2_2_2_2_Im[u][n]}; + if (l % 2 == 1) + r_u_v_alpha_delta[n] = c16mulShift(angle, table, 15); + else + r_u_v_alpha_delta_dmrs[n] = c16mulRealShift(c16mulShift(angle, table, 15), amp, 15); #ifdef DEBUG_NR_PUCCH_RX - printf("\t [nr_generate_pucch1] sequence generation \tu=%d \tv=%d \talpha=%lf \tr_u_v_alpha_delta[n=%d]=(%d,%d) \ty_n[n=%d]=(%d,%d)\n", - u,v,alpha,n,r_u_v_alpha_delta_re[n],r_u_v_alpha_delta_im[n],n,y_n_re[n],y_n_im[n]); + printf( + "\t [nr_generate_pucch1] sequence generation \tu=%d \tv=%d " + "\talpha=%lf \tr_u_v_alpha_delta[n=%d]=(%d,%d) " + "\ty_n[n=%d]=(%f,%f)\n", + u, + v, + alpha, + n, + r_u_v_alpha_delta[n].r, + r_u_v_alpha_delta[n].i, + n, + y_n[n].r, + y_n[n].i); #endif } /* @@ -691,298 +652,208 @@ void nr_decode_pucch1(c16_t **rxdataF, // the index of the orthogonal cover code is from a set determined as described in [4, TS 38.211] // and is indicated by higher layer parameter PUCCH-F1-time-domain-OCC // In the PUCCH_Config IE, the PUCCH-format1, timeDomainOCC field - uint8_t w_index = timeDomainOCC; - // N_SF_mprime_PUCCH_1 contains N_SF_mprime from table 6.3.2.4.1-1 (depending on number of PUCCH symbols nrofSymbols, mprime and intra-slot hopping enabled/disabled) - uint8_t N_SF_mprime_PUCCH_1; - // N_SF_mprime_PUCCH_1 contains N_SF_mprime from table 6.4.1.3.1.1-1 (depending on number of PUCCH symbols nrofSymbols, mprime and intra-slot hopping enabled/disabled) - uint8_t N_SF_mprime_PUCCH_DMRS_1; - // N_SF_mprime_PUCCH_1 contains N_SF_mprime from table 6.3.2.4.1-1 (depending on number of PUCCH symbols nrofSymbols, mprime=0 and intra-slot hopping enabled/disabled) - uint8_t N_SF_mprime0_PUCCH_1; - // N_SF_mprime_PUCCH_1 contains N_SF_mprime from table 6.4.1.3.1.1-1 (depending on number of PUCCH symbols nrofSymbols, mprime=0 and intra-slot hopping enabled/disabled) - uint8_t N_SF_mprime0_PUCCH_DMRS_1; - // mprime is 0 if no intra-slot hopping / mprime is {0,1} if intra-slot hopping - uint8_t mprime = 0; - - if (intraSlotFrequencyHopping == 0) { // intra-slot hopping disabled + const int w_index = timeDomainOCC; + if (intraSlotFrequencyHopping == false) { // intra-slot hopping disabled #ifdef DEBUG_NR_PUCCH_RX printf("\t [nr_generate_pucch1] block-wise spread with the orthogonal sequence wi(m) if intraSlotFrequencyHopping = %d, intra-slot hopping disabled\n", intraSlotFrequencyHopping); #endif - N_SF_mprime_PUCCH_1 = table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_noHop[nrofSymbols-1]; // only if intra-slot hopping not enabled (PUCCH) - N_SF_mprime_PUCCH_DMRS_1 = table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_noHop[nrofSymbols-1]; // only if intra-slot hopping not enabled (DM-RS) - N_SF_mprime0_PUCCH_1 = table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_noHop[nrofSymbols-1]; // only if intra-slot hopping not enabled mprime = 0 (PUCCH) - N_SF_mprime0_PUCCH_DMRS_1 = table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_noHop[nrofSymbols-1]; // only if intra-slot hopping not enabled mprime = 0 (DM-RS) + // mprime is 0 in this not hopping case + // N_SF_mprime_PUCCH_1 contains N_SF_mprime from table 6.3.2.4.1-1 + // (depending on number of PUCCH symbols nrofSymbols, mprime and + // intra-slot hopping enabled/disabled) N_SF_mprime_PUCCH_1 contains + // N_SF_mprime from table 6.4.1.3.1.1-1 (depending on number of PUCCH + // symbols nrofSymbols, mprime and intra-slot hopping enabled/disabled) + // N_SF_mprime_PUCCH_1 contains N_SF_mprime from table 6.3.2.4.1-1 + // (depending on number of PUCCH symbols nrofSymbols, mprime=0 and + // intra-slot hopping enabled/disabled) N_SF_mprime_PUCCH_1 contains + // N_SF_mprime from table 6.4.1.3.1.1-1 (depending on number of PUCCH + // symbols nrofSymbols, mprime=0 and intra-slot hopping enabled/disabled) + // mprime is 0 if no intra-slot hopping / mprime is {0,1} if intra-slot + // hopping + int N_SF_mprime_PUCCH_1 = + table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_noHop[nrofSymbols - 1]; // only if intra-slot hopping not enabled (PUCCH) + int N_SF_mprime_PUCCH_DMRS_1 = + table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_noHop[nrofSymbols - 1]; // only if intra-slot hopping not enabled (DM-RS) #ifdef DEBUG_NR_PUCCH_RX printf("\t [nr_generate_pucch1] w_index = %d, N_SF_mprime_PUCCH_1 = %d, N_SF_mprime_PUCCH_DMRS_1 = %d, N_SF_mprime0_PUCCH_1 = %d, N_SF_mprime0_PUCCH_DMRS_1 = %d\n", w_index, N_SF_mprime_PUCCH_1,N_SF_mprime_PUCCH_DMRS_1,N_SF_mprime0_PUCCH_1,N_SF_mprime0_PUCCH_DMRS_1); #endif + if(l%2==1){ for (int m=0; m < N_SF_mprime_PUCCH_1; m++) { - if(floor(l/2)*12==(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)){ - for (int n=0; n<12 ; n++) { - z_re_temp = (int16_t)(((((int32_t)(table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m])*z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15) - + (((int32_t)(table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m])*z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15))>>1); - z_im_temp = (int16_t)(((((int32_t)(table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m])*z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15) - - (((int32_t)(table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m])*z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15))>>1); - z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]=z_re_temp; - z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]=z_im_temp; - // printf("symbol=%d\tz_re_rx=%d\tz_im_rx=%d\t",l,(int)z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],(int)z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); -#ifdef DEBUG_NR_PUCCH_RX - printf("\t [nr_generate_pucch1] block-wise spread with wi(m) (mprime=%d, m=%d, n=%d) z[%d] = ((%d * %d - %d * %d), (%d * %d + %d * %d)) = (%d,%d)\n", - mprime, m, n, (mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n, - table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],y_n_re[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],y_n_im[n], - table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],y_n_im[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],y_n_re[n], - z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); -#endif - // multiplying with conjugate of low papr sequence - z_re_temp = (int16_t)(((((int32_t)(r_u_v_alpha_delta_re[n])*z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15) - + (((int32_t)(r_u_v_alpha_delta_im[n])*z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15))>>1); - z_im_temp = (int16_t)(((((int32_t)(r_u_v_alpha_delta_re[n])*z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15) - - (((int32_t)(r_u_v_alpha_delta_im[n])*z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15))>>1); - z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n] = z_re_temp; - z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n] = z_im_temp; - /* if(z_re_temp<0){ - printf("\nBug detection %d\t%d\t%d\t%d\n",r_u_v_alpha_delta_re[n],z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],(((int32_t)(r_u_v_alpha_delta_re[n])*z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15),(((int32_t)(r_u_v_alpha_delta_im[n])*z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15)); - } - printf("z1_re_rx=%d\tz1_im_rx=%d\n",(int)z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],(int)z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); */ - } - } + c16_t table = {table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m], + table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m]}; + if (l / 2 == m) { + for (int n = 0; n < 12; n++) { + c16_t *zPtr = z_rx + m * 12 + n; + *zPtr = c16MulConjShift(table, *zPtr, 15); + // multiplying with conjugate of low papr sequence + *zPtr = c16MulConjShift(r_u_v_alpha_delta[n], *zPtr, 16); + } + } } - } - - else{ + } else { for (int m=0; m < N_SF_mprime_PUCCH_DMRS_1; m++) { - if(floor(l/2)*12==(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)){ - for (int n=0; n<12 ; n++) { - z_dmrs_re_temp = (int16_t)(((((int32_t)(table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_DMRS_1][w_index][m])*z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15) - + (((int32_t)(table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_DMRS_1][w_index][m])*z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15))>>1); - z_dmrs_im_temp = (int16_t)(((((int32_t)(table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_DMRS_1][w_index][m])*z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15) - - (((int32_t)(table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_DMRS_1][w_index][m])*z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15))>>1); - z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n] = z_dmrs_re_temp; - z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n] = z_dmrs_im_temp; - // printf("symbol=%d\tz_dmrs_re_rx=%d\tz_dmrs_im_rx=%d\t",l,(int)z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],(int)z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); -#ifdef DEBUG_NR_PUCCH_RX - printf("\t [nr_generate_pucch1] block-wise spread with wi(m) (mprime=%d, m=%d, n=%d) z[%d] = ((%d * %d - %d * %d), (%d * %d + %d * %d)) = (%d,%d)\n", - mprime, m, n, (mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n, - table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_re[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_im[n], - table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_im[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_re[n], - z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); -#endif - //finding channel coeffcients by dividing received dmrs with actual dmrs and storing them in z_dmrs_re_rx and z_dmrs_im_rx arrays - z_dmrs_re_temp = (int16_t)(((((int32_t)(r_u_v_alpha_delta_dmrs_re[n])*z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15) - + (((int32_t)(r_u_v_alpha_delta_dmrs_im[n])*z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15))>>1); - z_dmrs_im_temp = (int16_t)(((((int32_t)(r_u_v_alpha_delta_dmrs_re[n])*z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15) - - (((int32_t)(r_u_v_alpha_delta_dmrs_im[n])*z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15))>>1); - /* if(z_dmrs_re_temp<0){ - printf("\nBug detection %d\t%d\t%d\t%d\n",r_u_v_alpha_delta_dmrs_re[n],z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],(((int32_t)(r_u_v_alpha_delta_dmrs_re[n])*z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15),(((int32_t)(r_u_v_alpha_delta_dmrs_im[n])*z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15)); - }*/ - z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n] = z_dmrs_re_temp; - z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n] = z_dmrs_im_temp; - // printf("z1_dmrs_re_rx=%d\tz1_dmrs_im_rx=%d\n",(int)z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],(int)z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); - /* z_dmrs_re_rx[(int)(l/2)*12+n]=z_dmrs_re_rx[(int)(l/2)*12+n]/r_u_v_alpha_delta_dmrs_re[n]; - z_dmrs_im_rx[(int)(l/2)*12+n]=z_dmrs_im_rx[(int)(l/2)*12+n]/r_u_v_alpha_delta_dmrs_im[n]; */ - } - } + const c16_t table = {table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_DMRS_1][w_index][m], + table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_DMRS_1][w_index][m]}; + if (l / 2 == m) { + for (int n = 0; n < 12; n++) { + c16_t *zDmrsPtr = z_dmrs_rx + m * 12 + n; + *zDmrsPtr = c16MulConjShift(table, *zDmrsPtr, 15); + // finding channel coeffcients by dividing received dmrs with actual dmrs and storing them in z_dmrs_re_rx and + // z_dmrs_im_rx arrays + *zDmrsPtr = c16MulConjShift(r_u_v_alpha_delta_dmrs[n], *zDmrsPtr, 16); + } + } } } } - if (intraSlotFrequencyHopping == 1) { // intra-slot hopping enabled + if (intraSlotFrequencyHopping == true) { // intra-slot hopping enabled #ifdef DEBUG_NR_PUCCH_RX printf("\t [nr_generate_pucch1] block-wise spread with the orthogonal sequence wi(m) if intraSlotFrequencyHopping = %d, intra-slot hopping enabled\n", intraSlotFrequencyHopping); #endif - N_SF_mprime_PUCCH_1 = table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_m0Hop[nrofSymbols-1]; // only if intra-slot hopping enabled mprime = 0 (PUCCH) - N_SF_mprime_PUCCH_DMRS_1 = table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_m0Hop[nrofSymbols-1]; // only if intra-slot hopping enabled mprime = 0 (DM-RS) - N_SF_mprime0_PUCCH_1 = table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_m0Hop[nrofSymbols-1]; // only if intra-slot hopping enabled mprime = 0 (PUCCH) - N_SF_mprime0_PUCCH_DMRS_1 = table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_m0Hop[nrofSymbols-1]; // only if intra-slot hopping enabled mprime = 0 (DM-RS) + // N_SF_mprime_PUCCH_1 contains N_SF_mprime from table 6.3.2.4.1-1 + // (depending on number of PUCCH symbols nrofSymbols, mprime and + // intra-slot hopping enabled/disabled) N_SF_mprime_PUCCH_1 contains + // N_SF_mprime from table 6.4.1.3.1.1-1 (depending on number of PUCCH + // symbols nrofSymbols, mprime and intra-slot hopping enabled/disabled) + // N_SF_mprime_PUCCH_1 contains N_SF_mprime from table 6.3.2.4.1-1 + // (depending on number of PUCCH symbols nrofSymbols, mprime=0 and + // intra-slot hopping enabled/disabled) N_SF_mprime_PUCCH_1 contains + // N_SF_mprime from table 6.4.1.3.1.1-1 (depending on number of PUCCH + // symbols nrofSymbols, mprime=0 and intra-slot hopping enabled/disabled) + // mprime is 0 if no intra-slot hopping / mprime is {0,1} if intra-slot + // hopping + int N_SF_mprime_PUCCH_1 = + table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_m0Hop[nrofSymbols - 1]; // only if intra-slot hopping enabled mprime = 0 (PUCCH) + int N_SF_mprime_PUCCH_DMRS_1 = + table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_m0Hop[nrofSymbols - 1]; // only if intra-slot hopping enabled mprime = 0 (DM-RS) + int N_SF_mprime0_PUCCH_1 = + table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_m0Hop[nrofSymbols - 1]; // only if intra-slot hopping enabled mprime = 0 (PUCCH) + int N_SF_mprime0_PUCCH_DMRS_1 = + table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_m0Hop[nrofSymbols - 1]; // only if intra-slot hopping enabled mprime = 0 (DM-RS) #ifdef DEBUG_NR_PUCCH_RX printf("\t [nr_generate_pucch1] w_index = %d, N_SF_mprime_PUCCH_1 = %d, N_SF_mprime_PUCCH_DMRS_1 = %d, N_SF_mprime0_PUCCH_1 = %d, N_SF_mprime0_PUCCH_DMRS_1 = %d\n", w_index, N_SF_mprime_PUCCH_1,N_SF_mprime_PUCCH_DMRS_1,N_SF_mprime0_PUCCH_1,N_SF_mprime0_PUCCH_DMRS_1); #endif - for (mprime = 0; mprime<2; mprime++) { // mprime can get values {0,1} - if(l%2==1){ - for (int m=0; m < N_SF_mprime_PUCCH_1; m++) { - if(floor(l/2)*12==(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)){ - for (int n=0; n<12 ; n++) { - z_re_temp = (int16_t)(((((int32_t)(table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m])*z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15) - + (((int32_t)(table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m])*z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15))>>1); - z_im_temp = (int16_t)(((((int32_t)(table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m])*z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15) - - (((int32_t)(table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m])*z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15))>>1); - z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n] = z_re_temp; - z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n] = z_im_temp; -#ifdef DEBUG_NR_PUCCH_RX - printf("\t [nr_generate_pucch1] block-wise spread with wi(m) (mprime=%d, m=%d, n=%d) z[%d] = ((%d * %d - %d * %d), (%d * %d + %d * %d)) = (%d,%d)\n", - mprime, m, n, (mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n, - table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],y_n_re[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],y_n_im[n], - table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],y_n_im[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],y_n_re[n], - z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); -#endif - z_re_temp = (int16_t)(((((int32_t)(r_u_v_alpha_delta_re[n])*z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15) - + (((int32_t)(r_u_v_alpha_delta_im[n])*z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15))>>1); - z_im_temp = (int16_t)(((((int32_t)(r_u_v_alpha_delta_re[n])*z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15) - - (((int32_t)(r_u_v_alpha_delta_im[n])*z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n])>>15))>>1); - z_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n] = z_re_temp; - z_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n] = z_im_temp; - } - } - } + for (int mprime = 0; mprime < 2; mprime++) { // mprime can get values {0,1} + if (l % 2 == 1) { + for (int m = 0; m < N_SF_mprime_PUCCH_1; m++) { + c16_t table = {table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m], + table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m]}; + if (floor(l / 2) * 12 == (mprime * 12 * N_SF_mprime0_PUCCH_1) + (m * 12)) { + for (int n = 0; n < 12; n++) { + c16_t *zPtr = z_rx + (mprime * 12 * N_SF_mprime0_PUCCH_1) + (m * 12) + n; + *zPtr = c16MulConjShift(table, *zPtr, 15); + *zPtr = c16MulConjShift(r_u_v_alpha_delta[n], *zPtr, 16); + } + } + } } - else{ - for (int m=0; m < N_SF_mprime_PUCCH_DMRS_1; m++) { - if(floor(l/2)*12==(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)){ - for (int n=0; n<12 ; n++) { - z_dmrs_re_temp = (int16_t)(((((int32_t)(table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_DMRS_1][w_index][m])*z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15) - + (((int32_t)(table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_DMRS_1][w_index][m])*z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15))>>1); - z_dmrs_im_temp = (int16_t)(((((int32_t)(table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_DMRS_1][w_index][m])*z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15) - - (((int32_t)(table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_DMRS_1][w_index][m])*z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15))>>1); - z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n] = z_dmrs_re_temp; - z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n] = z_dmrs_im_temp; -#ifdef DEBUG_NR_PUCCH_RX - printf("\t [nr_generate_pucch1] block-wise spread with wi(m) (mprime=%d, m=%d, n=%d) z[%d] = ((%d * %d - %d * %d), (%d * %d + %d * %d)) = (%d,%d)\n", - mprime, m, n, (mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n, - table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_re[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_im[n], - table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_im[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_re[n], - z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); -#endif - //finding channel coeffcients by dividing received dmrs with actual dmrs and storing them in z_dmrs_re_rx and z_dmrs_im_rx arrays - z_dmrs_re_temp = (int16_t)(((((int32_t)(r_u_v_alpha_delta_dmrs_re[n])*z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15) - + (((int32_t)(r_u_v_alpha_delta_dmrs_im[n])*z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15))>>1); - z_dmrs_im_temp = (int16_t)(((((int32_t)(r_u_v_alpha_delta_dmrs_re[n])*z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15) - - (((int32_t)(r_u_v_alpha_delta_dmrs_im[n])*z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n])>>15))>>1); - z_dmrs_re_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n] = z_dmrs_re_temp; - z_dmrs_im_rx[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n] = z_dmrs_im_temp; - - /* z_dmrs_re_rx[(int)(l/2)*12+n]=z_dmrs_re_rx[(int)(l/2)*12+n]/r_u_v_alpha_delta_dmrs_re[n]; - z_dmrs_im_rx[(int)(l/2)*12+n]=z_dmrs_im_rx[(int)(l/2)*12+n]/r_u_v_alpha_delta_dmrs_im[n]; */ - } - } - } + else { + for (int m = 0; m < N_SF_mprime_PUCCH_DMRS_1; m++) { + c16_t table = {table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m], + table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m]}; + if (floor(l / 2) * 12 == (mprime * 12 * N_SF_mprime0_PUCCH_DMRS_1) + (m * 12)) { + for (int n = 0; n < 12; n++) { + c16_t *zDmrsPtr = z_dmrs_rx + (mprime * 12 * N_SF_mprime0_PUCCH_DMRS_1) + (m * 12) + n; + *zDmrsPtr = c16MulConjShift(table, *zDmrsPtr, 15); + // finding channel coeffcients by dividing received dmrs with actual dmrs and storing them in z_dmrs_re_rx and + // z_dmrs_im_rx arrays + *zDmrsPtr = c16MulConjShift(r_u_v_alpha_delta_dmrs[n], *zDmrsPtr, 16); + } + } + } } - N_SF_mprime_PUCCH_1 = table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_m1Hop[nrofSymbols-1]; // only if intra-slot hopping enabled mprime = 1 (PUCCH) + N_SF_mprime_PUCCH_1 = + table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_m1Hop[nrofSymbols - 1]; // only if intra-slot hopping enabled mprime = 1 (PUCCH) N_SF_mprime_PUCCH_DMRS_1 = table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_m1Hop[nrofSymbols-1]; // only if intra-slot hopping enabled mprime = 1 (DM-RS) } } } - int16_t H_re[12],H_im[12],H1_re[12],H1_im[12]; - memset(H_re,0,12*sizeof(int16_t)); - memset(H_im,0,12*sizeof(int16_t)); - memset(H1_re,0,12*sizeof(int16_t)); - memset(H1_im,0,12*sizeof(int16_t)); - //averaging channel coefficients - for(l=0;l<=ceil(nrofSymbols/2);l++){ - if(intraSlotFrequencyHopping==0){ - for(int n=0;n<12;n++){ - H_re[n]=round(z_dmrs_re_rx[l*12+n]/ceil(nrofSymbols/2))+H_re[n]; - H_im[n]=round(z_dmrs_im_rx[l*12+n]/ceil(nrofSymbols/2))+H_im[n]; + cd_t H[12] = {0}, H1[12] = {0}; + const double half_nb_symbols = nrofSymbols / 2.0; + const double quarter_nb_symbols = nrofSymbols / 4.0; + for (int l = 0; l <= half_nb_symbols; l++) { + if (intraSlotFrequencyHopping == false) { + for (int n = 0; n < 12; n++) { + H[n].r += z_dmrs_rx[l * 12 + n].r / half_nb_symbols; + H[n].i += z_dmrs_rx[l * 12 + n].i / half_nb_symbols; + y_n[n].r += z_rx[l * 12 + n].r / half_nb_symbols; + y_n[n].i += z_rx[l * 12 + n].i / half_nb_symbols; } - } - else{ - if(l>15) + (((int32_t)(H_im[n])*y_n_im[n])>>15))>>1))/12)+d_re; - d_im = round(((int16_t)(((((int32_t)(H_re[n])*y_n_im[n])>>15) - (((int32_t)(H_im[n])*y_n_re[n])>>15))>>1))/12)+d_im; + cd_t d = {0}; + if (intraSlotFrequencyHopping == false) { + // complex-valued symbol d_re, d_im containing complex-valued symbol d(0): + for (int n = 0; n < 12; n++) { + d.r += H[n].r * y_n[n].r + H[n].i * y_n[n].i; + d.i += H[n].r * y_n[n].i - H[n].i * y_n[n].r; } - } - else{ - for(int n=0;n<12;n++){ - d_re = round(((int16_t)(((((int32_t)(H_re[n])*y_n_re[n])>>15) + (((int32_t)(H_im[n])*y_n_im[n])>>15))>>1))/12)+d_re; - d_im = round(((int16_t)(((((int32_t)(H_re[n])*y_n_im[n])>>15) - (((int32_t)(H_im[n])*y_n_re[n])>>15))>>1))/12)+d_im; - d1_re = round(((int16_t)(((((int32_t)(H1_re[n])*y1_n_re[n])>>15) + (((int32_t)(H1_im[n])*y1_n_im[n])>>15))>>1))/12)+d1_re; - d1_im = round(((int16_t)(((((int32_t)(H1_re[n])*y1_n_im[n])>>15) - (((int32_t)(H1_im[n])*y1_n_re[n])>>15))>>1))/12)+d1_im; + } else { + for (int n = 0; n < 12; n++) { + d.r += H[n].r * y_n[n].r + H[n].i * y_n[n].i; + d.i += H[n].r * y_n[n].i - H[n].i * y_n[n].r; + d.r += H[n].r * y1_n[n].r + H[n].i * y1_n[n].i; + d.i += H[n].r * y1_n[n].i - H[n].i * y1_n[n].r; } - d_re=round(d_re/2); - d_im=round(d_im/2); - d1_re=round(d1_re/2); - d1_im=round(d1_im/2); - d_re=d_re+d1_re; - d_im=d_im+d1_im; } //Decoding QPSK or BPSK symbols to obtain payload bits - if(nr_bit==1){ - if((d_re+d_im)>0){ - *payload=0; + if (nr_bit == 1) { + if ((d.r + d.i) > 0) { + *payload = 0; + } else { + *payload = 1; } - else{ - *payload=1; - } - } - else if(nr_bit==2){ - if((d_re>0)&&(d_im>0)){ - *payload=0; - } - else if((d_re<0)&&(d_im>0)){ - *payload=1; - } - else if((d_re>0)&&(d_im<0)){ - *payload=2; - } - else{ - *payload=3; + } else if (nr_bit == 2) { + if ((d.r > 0) && (d.i > 0)) { + *payload = 0; + } else if ((d.r < 0) && (d.i > 0)) { + *payload = 1; + } else if ((d.r > 0) && (d.i < 0)) { + *payload = 2; + } else { + *payload = 3; } } } -simde__m256i pucch2_3bit[8*2]; -simde__m256i pucch2_4bit[16*2]; -simde__m256i pucch2_5bit[32*2]; -simde__m256i pucch2_6bit[64*2]; -simde__m256i pucch2_7bit[128*2]; -simde__m256i pucch2_8bit[256*2]; -simde__m256i pucch2_9bit[512*2]; -simde__m256i pucch2_10bit[1024*2]; -simde__m256i pucch2_11bit[2048*2]; +static simde__m256i pucch2_3bit[8 * 2]; +static simde__m256i pucch2_4bit[16 * 2]; +static simde__m256i pucch2_5bit[32 * 2]; +static simde__m256i pucch2_6bit[64 * 2]; +static simde__m256i pucch2_7bit[128 * 2]; +static simde__m256i pucch2_8bit[256 * 2]; +static simde__m256i pucch2_9bit[512 * 2]; +static simde__m256i pucch2_10bit[1024 * 2]; +static simde__m256i pucch2_11bit[2048 * 2]; -static simde__m256i *pucch2_lut[9]={pucch2_3bit, - pucch2_4bit, - pucch2_5bit, - pucch2_6bit, - pucch2_7bit, - pucch2_8bit, - pucch2_9bit, - pucch2_10bit, - pucch2_11bit}; +static simde__m256i *pucch2_lut[9] = + {pucch2_3bit, pucch2_4bit, pucch2_5bit, pucch2_6bit, pucch2_7bit, pucch2_8bit, pucch2_9bit, pucch2_10bit, pucch2_11bit}; simde__m64 pucch2_polar_4bit[16]; simde__m128i pucch2_polar_llr_num_lut[256],pucch2_polar_llr_den_lut[256]; @@ -993,8 +864,8 @@ void init_pucch2_luts() { int8_t bit; for (int b=3;b<12;b++) { - for (uint16_t i=0;i<(1< 0 ? -1 : 1; @@ -1082,47 +953,48 @@ void init_pucch2_luts() { simde__m128i *lut_num_i=&pucch2_polar_llr_num_lut[i]; simde__m128i *lut_den_i=&pucch2_polar_llr_den_lut[i]; bit = (i&0x1) > 0 ? 0 : 1; - *lut_num_i = simde_mm_insert_epi16(*lut_num_i,bit,0); - *lut_den_i = simde_mm_insert_epi16(*lut_den_i,1-bit,0); + *lut_num_i = simde_mm_insert_epi16(*lut_num_i, bit, 0); + *lut_den_i = simde_mm_insert_epi16(*lut_den_i, 1 - bit, 0); bit = (i&0x10) > 0 ? 0 : 1; - *lut_num_i = simde_mm_insert_epi16(*lut_num_i,bit,1); - *lut_den_i = simde_mm_insert_epi16(*lut_den_i,1-bit,1); + *lut_num_i = simde_mm_insert_epi16(*lut_num_i, bit, 1); + *lut_den_i = simde_mm_insert_epi16(*lut_den_i, 1 - bit, 1); bit = (i&0x2) > 0 ? 0 : 1; - *lut_num_i = simde_mm_insert_epi16(*lut_num_i,bit,2); - *lut_den_i = simde_mm_insert_epi16(*lut_den_i,1-bit,2); + *lut_num_i = simde_mm_insert_epi16(*lut_num_i, bit, 2); + *lut_den_i = simde_mm_insert_epi16(*lut_den_i, 1 - bit, 2); bit = (i&0x20) > 0 ? 0 : 1; - *lut_num_i = simde_mm_insert_epi16(*lut_num_i,bit,3); - *lut_den_i = simde_mm_insert_epi16(*lut_den_i,1-bit,3); + *lut_num_i = simde_mm_insert_epi16(*lut_num_i, bit, 3); + *lut_den_i = simde_mm_insert_epi16(*lut_den_i, 1 - bit, 3); bit = (i&0x4) > 0 ? 0 : 1; - *lut_num_i = simde_mm_insert_epi16(*lut_num_i,bit,4); - *lut_den_i = simde_mm_insert_epi16(*lut_den_i,1-bit,4); + *lut_num_i = simde_mm_insert_epi16(*lut_num_i, bit, 4); + *lut_den_i = simde_mm_insert_epi16(*lut_den_i, 1 - bit, 4); bit = (i&0x40) > 0 ? 0 : 1; - *lut_num_i = simde_mm_insert_epi16(*lut_num_i,bit,5); - *lut_den_i = simde_mm_insert_epi16(*lut_den_i,1-bit,5); + *lut_num_i = simde_mm_insert_epi16(*lut_num_i, bit, 5); + *lut_den_i = simde_mm_insert_epi16(*lut_den_i, 1 - bit, 5); bit = (i&0x8) > 0 ? 0 : 1; - *lut_num_i = simde_mm_insert_epi16(*lut_num_i,bit,6); - *lut_den_i = simde_mm_insert_epi16(*lut_den_i,1-bit,6); + *lut_num_i = simde_mm_insert_epi16(*lut_num_i, bit, 6); + *lut_den_i = simde_mm_insert_epi16(*lut_den_i, 1 - bit, 6); bit = (i&0x80) > 0 ? 0 : 1; - *lut_num_i = simde_mm_insert_epi16(*lut_num_i,bit,7); - *lut_den_i = simde_mm_insert_epi16(*lut_den_i,1-bit,7); + *lut_num_i = simde_mm_insert_epi16(*lut_num_i, bit, 7); + *lut_den_i = simde_mm_insert_epi16(*lut_den_i, 1 - bit, 7); #ifdef DEBUG_NR_PUCCH_RX - printf("i %d, lut_num (%d,%d,%d,%d,%d,%d,%d,%d)\n",i, - ((int16_t *)lut_num_i)[0], - ((int16_t *)lut_num_i)[1], - ((int16_t *)lut_num_i)[2], - ((int16_t *)lut_num_i)[3], - ((int16_t *)lut_num_i)[4], - ((int16_t *)lut_num_i)[5], - ((int16_t *)lut_num_i)[6], - ((int16_t *)lut_num_i)[7]); + printf("i %d, lut_num (%d,%d,%d,%d,%d,%d,%d,%d)\n", + i, + ((int16_t *)lut_num_i)[0], + ((int16_t *)lut_num_i)[1], + ((int16_t *)lut_num_i)[2], + ((int16_t *)lut_num_i)[3], + ((int16_t *)lut_num_i)[4], + ((int16_t *)lut_num_i)[5], + ((int16_t *)lut_num_i)[6], + ((int16_t *)lut_num_i)[7]); #endif } } @@ -1138,8 +1010,9 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; //pucch_GroupHopping_t pucch_GroupHopping = pucch_pdu->group_hop_flag + (pucch_pdu->sequence_hop_flag<<1); - AssertFatal(pucch_pdu->nr_of_symbols==1 || pucch_pdu->nr_of_symbols==2, - "Illegal number of symbols for PUCCH 2 %d\n",pucch_pdu->nr_of_symbols); + AssertFatal(pucch_pdu->nr_of_symbols == 1 || pucch_pdu->nr_of_symbols == 2, + "Illegal number of symbols for PUCCH 2 %d\n", + pucch_pdu->nr_of_symbols); AssertFatal((pucch_pdu->prb_start-((pucch_pdu->prb_start>>2)<<2))==0, "Current pucch2 receiver implementation requires a PRB offset multiple of 4. The one selected is %d", @@ -1147,21 +1020,26 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, //extract pucch and dmrs first - int l2=pucch_pdu->start_symbol_index; - int re_offset[2]; - re_offset[0] = 12*(pucch_pdu->prb_start+pucch_pdu->bwp_start) + frame_parms->first_carrier_offset; - int soffset=(slot&3)*frame_parms->symbols_per_slot*frame_parms->ofdm_symbol_size; + int l2 = pucch_pdu->start_symbol_index; + int soffset = (slot & 3) * frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size; + + int re_offset[2]; + re_offset[0] = + (12 * (pucch_pdu->prb_start + pucch_pdu->bwp_start) + frame_parms->first_carrier_offset) % frame_parms->ofdm_symbol_size; if (re_offset[0]>= frame_parms->ofdm_symbol_size) re_offset[0]-=frame_parms->ofdm_symbol_size; - if (pucch_pdu->freq_hop_flag == 0) re_offset[1] = re_offset[0]; + if (pucch_pdu->freq_hop_flag == 0) + re_offset[1] = re_offset[0]; else { re_offset[1] = 12*(pucch_pdu->second_hop_prb+pucch_pdu->bwp_start) + frame_parms->first_carrier_offset; if (re_offset[1]>= frame_parms->ofdm_symbol_size) re_offset[1]-=frame_parms->ofdm_symbol_size; } - AssertFatal(pucch_pdu->prb_size*pucch_pdu->nr_of_symbols > 1,"number of PRB*SYMB (%d,%d)< 2", - pucch_pdu->prb_size,pucch_pdu->nr_of_symbols); + AssertFatal(pucch_pdu->prb_size * pucch_pdu->nr_of_symbols > 1, + "number of PRB*SYMB (%d,%d)< 2", + pucch_pdu->prb_size, + pucch_pdu->nr_of_symbols); int Prx = gNB->gNB_config.carrier_config.num_rx_ant.value; // AssertFatal((pucch_pdu->prb_size&1) == 0,"prb_size %d is not a multiple of2\n",pucch_pdu->prb_size); @@ -1216,7 +1094,7 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, // if the number of PRBs is odd // we fill the unsed part of the arrays for (int aa = 0; aa < Prx; aa++) { - for (int symb=0; symbnr_of_symbols;symb++) { + for (int symb = 0; symb < pucch_pdu->nr_of_symbols; symb++) { const int sz = pucch_pdu->prb_size; memset(r_re_ext[aa][symb] + 8 * sz, 0, 8 * sizeof(int16_t)); memset(r_im_ext[aa][symb] + 8 * sz, 0, 8 * sizeof(int16_t)); @@ -1228,7 +1106,7 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, for (int symb=0; symbnr_of_symbols;symb++) { // 24 REs contains 48x16-bit, so 6x8x16-bit - for (int aa=0;aaprb_size; prb++) { int16_t *r_re_ext_p = &r_re_ext[aa][symb][8 * prb]; int16_t *r_im_ext_p = &r_im_ext[aa][symb][8 * prb]; @@ -1272,7 +1150,7 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, reset = 0; } - for (int group=0;group>=5; + /* corr32_re[group][aa]>>=5; corr32_im[group][aa]>>=5;*/ #ifdef DEBUG_NR_PUCCH_RX printf("Group %d: corr32 (%d,%d)\n",group,corr32_re[symb][group][aa],corr32_im[symb][group][aa]); @@ -1358,7 +1235,7 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, sGold = lte_gold_generic(&x1, &x2, 1); uint8_t *sGold8 = (uint8_t *)&sGold; #ifdef DEBUG_NR_PUCCH_RX - printf("x2 %x, s %x\n",x2,s); + printf("x2 %x\n", x2); #endif for (int symb=0;symbnr_of_symbols;symb++) { simde__m64 c_re[4], c_im[4]; @@ -1477,9 +1354,9 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, #ifdef DEBUG_NR_PUCCH_RX printf("cw %d:",cw); for (int i=0;i<32;i+=2) { - printf("%d,%d,", - ((int16_t*)&pucch2_lut[nb_bit-3][cw<<1])[i>>1], - ((int16_t*)&pucch2_lut[nb_bit-3][cw<<1])[1+(i>>1)]); + printf("%d,%d,", + ((int16_t *)&pucch2_lut[nb_bit - 3][cw << 1])[i >> 1], + ((int16_t *)&pucch2_lut[nb_bit - 3][cw << 1])[1 + (i >> 1)]); } printf("\n"); #endif @@ -1489,10 +1366,12 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, for (int group=0;group (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)\n",aa, ((int16_t*)&prod_re[aa])[0],((int16_t*)&prod_re[aa])[1],((int16_t*)&prod_re[aa])[2],((int16_t*)&prod_re[aa])[3], @@ -1513,7 +1392,7 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, ((int16_t*)&prod_re[aa])[4],((int16_t*)&prod_re[aa])[5],((int16_t*)&prod_re[aa])[6],((int16_t*)&prod_re[aa])[7], ((int16_t*)&prod_re[aa])[8],((int16_t*)&prod_re[aa])[9],((int16_t*)&prod_re[aa])[10],((int16_t*)&prod_re[aa])[11], ((int16_t*)&prod_re[aa])[12],((int16_t*)&prod_re[aa])[13],((int16_t*)&prod_re[aa])[14],((int16_t*)&prod_re[aa])[15]); -#endif +#endif prod_im[aa] = simde_mm256_hadds_epi16(prod_im[aa],prod_im[aa]); prod_re[aa] = simde_mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1+2+3 #ifdef DEBUG_NR_PUCCH_RX @@ -1522,7 +1401,7 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, ((int16_t*)&prod_re[aa])[4],((int16_t*)&prod_re[aa])[5],((int16_t*)&prod_re[aa])[6],((int16_t*)&prod_re[aa])[7], ((int16_t*)&prod_re[aa])[8],((int16_t*)&prod_re[aa])[9],((int16_t*)&prod_re[aa])[10],((int16_t*)&prod_re[aa])[11], ((int16_t*)&prod_re[aa])[12],((int16_t*)&prod_re[aa])[13],((int16_t*)&prod_re[aa])[14],((int16_t*)&prod_re[aa])[15]); -#endif +#endif prod_im[aa] = simde_mm256_hadds_epi16(prod_im[aa],prod_im[aa]); prod_re[aa] = simde_mm256_hadds_epi16(prod_re[aa],prod_re[aa]);// 0+1+2+3+4+5+6+7 #ifdef DEBUG_NR_PUCCH_RX @@ -1531,7 +1410,7 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, ((int16_t*)&prod_re[aa])[4],((int16_t*)&prod_re[aa])[5],((int16_t*)&prod_re[aa])[6],((int16_t*)&prod_re[aa])[7], ((int16_t*)&prod_re[aa])[8],((int16_t*)&prod_re[aa])[9],((int16_t*)&prod_re[aa])[10],((int16_t*)&prod_re[aa])[11], ((int16_t*)&prod_re[aa])[12],((int16_t*)&prod_re[aa])[13],((int16_t*)&prod_re[aa])[14],((int16_t*)&prod_re[aa])[15]); -#endif +#endif prod_im[aa] = simde_mm256_hadds_epi16(prod_im[aa],prod_im[aa]); } int64_t corr_re=0,corr_im=0; @@ -1542,12 +1421,16 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, corr_re = ( corr32_re[symb][group][aa]+((int16_t*)(&prod_re[aa]))[0]+((int16_t*)(&prod_re[aa]))[8]); corr_im = ( corr32_im[symb][group][aa]+((int16_t*)(&prod_im[aa]))[0]+((int16_t*)(&prod_im[aa]))[8]); #ifdef DEBUG_NR_PUCCH_RX - printf("pucch2 cw %d group %d aa %d: (%d,%d)+(%d,%d) = (%ld,%ld)\n",cw,group,aa, - corr32_re[symb][group][aa],corr32_im[symb][group][aa], - ((int16_t*)(&prod_re[aa]))[0]+((int16_t*)(&prod_re[aa]))[8], - ((int16_t*)(&prod_im[aa]))[0]+((int16_t*)(&prod_im[aa]))[8], - corr_re,corr_im - ); + printf("pucch2 cw %d group %d aa %d: (%d,%d)+(%d,%d) = (%ld,%ld)\n", + cw, + group, + aa, + corr32_re[symb][group][aa], + corr32_im[symb][group][aa], + ((int16_t *)(&prod_re[aa]))[0] + ((int16_t *)(&prod_re[aa]))[8], + ((int16_t *)(&prod_im[aa]))[0] + ((int16_t *)(&prod_im[aa]))[8], + corr_re, + corr_im); #endif @@ -1556,10 +1439,10 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, }// group loop } // symb loop if (corr_tmp > corr) { - corr = corr_tmp; - cw_ML=cw; + corr = corr_tmp; + cw_ML = cw; #ifdef DEBUG_NR_PUCCH_RX - printf("slot %d PUCCH2 cw_ML %d, corr %lu\n",slot,cw_ML,corr); + printf("slot %d PUCCH2 cw_ML %d, corr %lu\n", slot, cw_ML, corr); #endif } } // cw loop @@ -1592,8 +1475,7 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, printf("cw %d:",cw); for (int i=0;i<4;i++) { - printf("%d,", - ((int16_t*)&pucch2_polar_4bit[cw])[i>>1]); + printf("%d,", ((int16_t *)&pucch2_polar_4bit[cw])[i >> 1]); } printf("\n"); } @@ -1609,10 +1491,14 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, for (int cw=0;cw<256;cw++) { corr_tmp=0; for (int aa=0;aa>4],rp_im[aa][symb][half_prb])),5); - prod_im[aa] = simde_mm_srai_pi16(simde_mm_subs_pi16(simde_mm_mullo_pi16(pucch2_polar_4bit[cw&15],rp2_im[aa][symb][half_prb]), - simde_mm_mullo_pi16(pucch2_polar_4bit[cw>>4],rp2_re[aa][symb][half_prb])),5); + prod_re[aa] = + simde_mm_srai_pi16(simde_mm_adds_pi16(simde_mm_mullo_pi16(pucch2_polar_4bit[cw & 15], rp_re[aa][symb][half_prb]), + simde_mm_mullo_pi16(pucch2_polar_4bit[cw >> 4], rp_im[aa][symb][half_prb])), + 5); + prod_im[aa] = + simde_mm_srai_pi16(simde_mm_subs_pi16(simde_mm_mullo_pi16(pucch2_polar_4bit[cw & 15], rp2_im[aa][symb][half_prb]), + simde_mm_mullo_pi16(pucch2_polar_4bit[cw >> 4], rp2_re[aa][symb][half_prb])), + 5); prod_re[aa] = simde_mm_hadds_pi16(prod_re[aa],prod_re[aa]);// 0+1 prod_im[aa] = simde_mm_hadds_pi16(prod_im[aa],prod_im[aa]); prod_re[aa] = simde_mm_hadds_pi16(prod_re[aa],prod_re[aa]);// 0+1+2+3 @@ -1626,63 +1512,65 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, corr_re = ( corr32_re[symb][half_prb>>2][aa]/(2*nc_group_size*4/2)+((int16_t*)(&prod_re[aa]))[0]); corr_im = ( corr32_im[symb][half_prb>>2][aa]/(2*nc_group_size*4/2)+((int16_t*)(&prod_im[aa]))[0]); corr_tmp += corr_re*corr_re + corr_im*corr_im; - /* - LOG_D(PHY,"pucch2 half_prb %d cw %d (%d,%d) aa %d: (%d,%d,%d,%d,%d,%d,%d,%d)x(%d,%d,%d,%d,%d,%d,%d,%d) (%d,%d)+(%d,%d) = (%d,%d) => %d\n", - half_prb,cw,cw&15,cw>>4,aa, + /* + LOG_D(PHY,"pucch2 half_prb %d cw %d (%d,%d) aa %d: (%d,%d,%d,%d,%d,%d,%d,%d)x(%d,%d,%d,%d,%d,%d,%d,%d) (%d,%d)+(%d,%d) + = (%d,%d) => %d\n", half_prb,cw,cw&15,cw>>4,aa, ((int16_t*)&pucch2_polar_4bit[cw&15])[0],((int16_t*)&pucch2_polar_4bit[cw>>4])[0], ((int16_t*)&pucch2_polar_4bit[cw&15])[1],((int16_t*)&pucch2_polar_4bit[cw>>4])[1], ((int16_t*)&pucch2_polar_4bit[cw&15])[2],((int16_t*)&pucch2_polar_4bit[cw>>4])[2], - ((int16_t*)&pucch2_polar_4bit[cw&15])[3],((int16_t*)&pucch2_polar_4bit[cw>>4])[3], - ((int16_t*)&rp_re[aa][half_prb])[0],((int16_t*)&rp_im[aa][half_prb])[0], - ((int16_t*)&rp_re[aa][half_prb])[1],((int16_t*)&rp_im[aa][half_prb])[1], - ((int16_t*)&rp_re[aa][half_prb])[2],((int16_t*)&rp_im[aa][half_prb])[2], - ((int16_t*)&rp_re[aa][half_prb])[3],((int16_t*)&rp_im[aa][half_prb])[3], - corr32_re[half_prb>>2][aa]/(2*nc_group_size*4/2),corr32_im[half_prb>>2][aa]/(2*nc_group_size*4/2), - ((int16_t*)(&prod_re[aa]))[0], - ((int16_t*)(&prod_im[aa]))[0], - corr_re, - corr_im, - corr_tmp); -*/ - } - corr16 = simde_mm_set1_epi16((int16_t)(corr_tmp>>8)); + ((int16_t*)&pucch2_polar_4bit[cw&15])[3],((int16_t*)&pucch2_polar_4bit[cw>>4])[3], + ((int16_t*)&rp_re[aa][half_prb])[0],((int16_t*)&rp_im[aa][half_prb])[0], + ((int16_t*)&rp_re[aa][half_prb])[1],((int16_t*)&rp_im[aa][half_prb])[1], + ((int16_t*)&rp_re[aa][half_prb])[2],((int16_t*)&rp_im[aa][half_prb])[2], + ((int16_t*)&rp_re[aa][half_prb])[3],((int16_t*)&rp_im[aa][half_prb])[3], + corr32_re[half_prb>>2][aa]/(2*nc_group_size*4/2),corr32_im[half_prb>>2][aa]/(2*nc_group_size*4/2), + ((int16_t*)(&prod_re[aa]))[0], + ((int16_t*)(&prod_im[aa]))[0], + corr_re, + corr_im, + corr_tmp); + */ + } + corr16 = simde_mm_set1_epi16((int16_t)(corr_tmp >> 8)); - LOG_D(PHY,"half_prb %d cw %d corr16 %d\n",half_prb,cw,corr_tmp>>8); + LOG_D(PHY, "half_prb %d cw %d corr16 %d\n", half_prb, cw, corr_tmp >> 8); - llr_num = simde_mm_max_epi16(simde_mm_mullo_epi16(corr16,pucch2_polar_llr_num_lut[cw]),llr_num); - llr_den = simde_mm_max_epi16(simde_mm_mullo_epi16(corr16,pucch2_polar_llr_den_lut[cw]),llr_den); + llr_num = simde_mm_max_epi16(simde_mm_mullo_epi16(corr16, pucch2_polar_llr_num_lut[cw]), llr_num); + llr_den = simde_mm_max_epi16(simde_mm_mullo_epi16(corr16, pucch2_polar_llr_den_lut[cw]), llr_den); - LOG_D(PHY,"lut_num (%d,%d,%d,%d,%d,%d,%d,%d)\n", - ((int16_t*)&pucch2_polar_llr_num_lut[cw])[0], - ((int16_t*)&pucch2_polar_llr_num_lut[cw])[1], - ((int16_t*)&pucch2_polar_llr_num_lut[cw])[2], - ((int16_t*)&pucch2_polar_llr_num_lut[cw])[3], - ((int16_t*)&pucch2_polar_llr_num_lut[cw])[4], - ((int16_t*)&pucch2_polar_llr_num_lut[cw])[5], - ((int16_t*)&pucch2_polar_llr_num_lut[cw])[6], - ((int16_t*)&pucch2_polar_llr_num_lut[cw])[7]); + LOG_D(PHY, + "lut_num (%d,%d,%d,%d,%d,%d,%d,%d)\n", + ((int16_t *)&pucch2_polar_llr_num_lut[cw])[0], + ((int16_t *)&pucch2_polar_llr_num_lut[cw])[1], + ((int16_t *)&pucch2_polar_llr_num_lut[cw])[2], + ((int16_t *)&pucch2_polar_llr_num_lut[cw])[3], + ((int16_t *)&pucch2_polar_llr_num_lut[cw])[4], + ((int16_t *)&pucch2_polar_llr_num_lut[cw])[5], + ((int16_t *)&pucch2_polar_llr_num_lut[cw])[6], + ((int16_t *)&pucch2_polar_llr_num_lut[cw])[7]); - LOG_D(PHY,"llr_num (%d,%d,%d,%d,%d,%d,%d,%d)\n", - ((int16_t*)&llr_num)[0], - ((int16_t*)&llr_num)[1], - ((int16_t*)&llr_num)[2], - ((int16_t*)&llr_num)[3], - ((int16_t*)&llr_num)[4], - ((int16_t*)&llr_num)[5], - ((int16_t*)&llr_num)[6], - ((int16_t*)&llr_num)[7]); - LOG_D(PHY,"llr_den (%d,%d,%d,%d,%d,%d,%d,%d)\n", - ((int16_t*)&llr_den)[0], - ((int16_t*)&llr_den)[1], - ((int16_t*)&llr_den)[2], - ((int16_t*)&llr_den)[3], - ((int16_t*)&llr_den)[4], - ((int16_t*)&llr_den)[5], - ((int16_t*)&llr_den)[6], - ((int16_t*)&llr_den)[7]); - - } - // compute llrs + LOG_D(PHY, + "llr_num (%d,%d,%d,%d,%d,%d,%d,%d)\n", + ((int16_t *)&llr_num)[0], + ((int16_t *)&llr_num)[1], + ((int16_t *)&llr_num)[2], + ((int16_t *)&llr_num)[3], + ((int16_t *)&llr_num)[4], + ((int16_t *)&llr_num)[5], + ((int16_t *)&llr_num)[6], + ((int16_t *)&llr_num)[7]); + LOG_D(PHY, + "llr_den (%d,%d,%d,%d,%d,%d,%d,%d)\n", + ((int16_t *)&llr_den)[0], + ((int16_t *)&llr_den)[1], + ((int16_t *)&llr_den)[2], + ((int16_t *)&llr_den)[3], + ((int16_t *)&llr_den)[4], + ((int16_t *)&llr_den)[5], + ((int16_t *)&llr_den)[6], + ((int16_t *)&llr_den)[7]); + } + // compute llrs llrs[half_prb + (symb*2*pucch_pdu->prb_size)] = simde_mm_subs_epi16(llr_num,llr_den); LOG_D(PHY,"llrs[%d] : (%d,%d,%d,%d,%d,%d,%d,%d)\n", half_prb, @@ -1712,9 +1600,10 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, // estimate CQI for MAC (from antenna port 0 only) // TODO this computation is wrong -> to be ignored at MAC for now - int SNRtimes10 = dB_fixed_times10(signal_energy_nodc((int32_t *)&rxdataF[0][soffset+(l2*frame_parms->ofdm_symbol_size)+re_offset[0]], - 12*pucch_pdu->prb_size)) - - (10*gNB->measurements.n0_power_tot_dB); + int SNRtimes10 = + dB_fixed_times10(signal_energy_nodc((int32_t *)&rxdataF[0][soffset + (l2 * frame_parms->ofdm_symbol_size) + re_offset[0]], + 12 * pucch_pdu->prb_size)) + - (10 * gNB->measurements.n0_power_tot_dB); int cqi,bit_left; if (SNRtimes10 < -640) cqi=0; else if (SNRtimes10 > 635) cqi=255; @@ -1739,14 +1628,12 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, int i=0; for (;iharq.harq_payload[i] = decodedPayload[0] & 255; - LOG_D(PHY,"[DLSCH/PDSCH/PUCCH2] %d.%d HARQ paylod (%d) = %d\n", - frame,slot,i,uci_pdu->harq.harq_payload[i]); + LOG_D(PHY, "[DLSCH/PDSCH/PUCCH2] %d.%d HARQ payload (%d) = %d\n", frame, slot, i, uci_pdu->harq.harq_payload[i]); decodedPayload[0]>>=8; } bit_left = pucch_pdu->bit_len_harq-((harq_bytes-1)<<3); uci_pdu->harq.harq_payload[i] = decodedPayload[0] & ((1<harq.harq_payload[i]); + LOG_D(PHY, "[DLSCH/PDSCH/PUCCH2] %d.%d HARQ payload (%d) = %d\n", frame, slot, i, uci_pdu->harq.harq_payload[i]); decodedPayload[0] >>= pucch_pdu->bit_len_harq; } diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c index b73d432f2e..19f7e89a7f 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c @@ -54,7 +54,7 @@ void nr_generate_pucch0(const PHY_VARS_NR_UE *ue, c16_t **txdataF, const NR_DL_FRAME_PARMS *frame_parms, - const int16_t amp, + const int16_t amp16, const int nr_slot_tx, const fapi_nr_ul_config_pucch_pdu *pucch_pdu) { @@ -72,13 +72,14 @@ void nr_generate_pucch0(const PHY_VARS_NR_UE *ue, * Defining cyclic shift hopping TS 38.211 Subclause 6.3.2.2.2 */ // alpha is cyclic shift - double alpha; - // lnormal is the OFDM symbol number in the PUCCH transmission where l=0 corresponds to the first OFDM symbol of the PUCCH transmission - //uint8_t lnormal; - // lprime is the index of the OFDM symbol in the slot that corresponds to the first OFDM symbol of the PUCCH transmission in the slot given by [5, TS 38.213] - //uint8_t lprime; + // lnormal is the OFDM symbol number in the PUCCH transmission where l=0 corresponds to the first OFDM symbol of the PUCCH + // transmission + // uint8_t lnormal; + // lprime is the index of the OFDM symbol in the slot that corresponds to the first OFDM symbol of the PUCCH transmission in the + // slot given by [5, TS 38.213] + // uint8_t lprime; // mcs is provided by TC 38.213 subclauses 9.2.3, 9.2.4, 9.2.5 FIXME! - //uint8_t mcs; + // uint8_t mcs; /* * in TS 38.213 Subclause 9.2.1 it is said that: * for PUCCH format 0 or PUCCH format 1, the index of the cyclic shift @@ -89,7 +90,7 @@ void nr_generate_pucch0(const PHY_VARS_NR_UE *ue, * x(l*12+n) = r_u_v_alpha_delta(n) */ // the value of u,v (delta always 0 for PUCCH) has to be calculated according to TS 38.211 Subclause 6.3.2.2.1 - uint8_t u[2]={0,0},v[2]={0,0}; + uint8_t u[2] = {0}, v[2] = {0}; LOG_D(PHY,"pucch0: slot %d nr_symbols %d, start_symbol %d, prb_start %d, second_hop_prb %d, group_hop_flag %d, sequence_hop_flag %d, mcs %d\n", nr_slot_tx,pucch_pdu->nr_of_symbols,pucch_pdu->start_symbol_index,pucch_pdu->prb_start,pucch_pdu->second_hop_prb,pucch_pdu->group_hop_flag,pucch_pdu->sequence_hop_flag,pucch_pdu->mcs); @@ -97,70 +98,55 @@ void nr_generate_pucch0(const PHY_VARS_NR_UE *ue, #ifdef DEBUG_NR_PUCCH_TX printf("\t [nr_generate_pucch0] sequence generation: variable initialization for test\n"); #endif - // x_n contains the sequence r_u_v_alpha_delta(n) - int16_t x_n_re[2][24],x_n_im[2][24]; - - uint16_t startingPRB = pucch_pdu->prb_start + pucch_pdu->bwp_start; + int startingPRB = pucch_pdu->prb_start + pucch_pdu->bwp_start; pucch_GroupHopping_t pucch_GroupHopping = pucch_pdu->group_hop_flag + (pucch_pdu->sequence_hop_flag<<1); // we proceed to calculate alpha according to TS 38.211 Subclause 6.3.2.2.2 int prb_offset[2]={startingPRB,startingPRB}; - nr_group_sequence_hopping(pucch_GroupHopping,pucch_pdu->hopping_id,0,nr_slot_tx,&u[0],&v[0]); // calculating u and v value + nr_group_sequence_hopping(pucch_GroupHopping, pucch_pdu->hopping_id, 0, nr_slot_tx, u, v); // calculating u and v value if (pucch_pdu->freq_hop_flag == 1) { - nr_group_sequence_hopping(pucch_GroupHopping,pucch_pdu->hopping_id,1,nr_slot_tx,&u[1],&v[1]); // calculating u and v value + nr_group_sequence_hopping(pucch_GroupHopping, pucch_pdu->hopping_id, 1, nr_slot_tx, u + 1, v + 1); // calculating u and v value prb_offset[1] = pucch_pdu->second_hop_prb + pucch_pdu->bwp_start; } - for (int l=0; lnr_of_symbols; l++) { - alpha = nr_cyclic_shift_hopping(pucch_pdu->hopping_id, - pucch_pdu->initial_cyclic_shift, - pucch_pdu->mcs,l, - pucch_pdu->start_symbol_index, - nr_slot_tx); -#ifdef DEBUG_NR_PUCCH_TX - printf("\t [nr_generate_pucch0] sequence generation \tu=%d \tv=%d \talpha=%lf \t(for symbol l=%d)\n",u[l],v[l],alpha,l); -#endif - - for (int n=0; n<12; n++) { - x_n_re[l][n] = (int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Re[u[l]][n])>>15) - - (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Im[u[l]][n])>>15))); // Re part of base sequence shifted by alpha - x_n_im[l][n] = (int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Im[u[l]][n])>>15) - + (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Re[u[l]][n])>>15))); // Im part of base sequence shifted by alpha -#ifdef DEBUG_NR_PUCCH_TX - printf("\t [nr_generate_pucch0] sequence generation \tu=%d \tv=%d \talpha=%lf \tx_n(l=%d,n=%d)=(%d,%d)\n", - u[l],v[l],alpha,l,n,x_n_re[l][n],x_n_im[l][n]); -#endif - } - } - /* * Implementing TS 38.211 Subclause 6.3.2.3.2 Mapping to physical resources FIXME! */ - //int32_t *txptr; - uint32_t re_offset=0; - uint8_t l2; for (int l=0; lnr_of_symbols; l++) { - l2=l+pucch_pdu->start_symbol_index; - re_offset = (12*prb_offset[l]) + frame_parms->first_carrier_offset; + const double alpha = nr_cyclic_shift_hopping(pucch_pdu->hopping_id, + pucch_pdu->initial_cyclic_shift, + pucch_pdu->mcs, + l, + pucch_pdu->start_symbol_index, + nr_slot_tx); + int l2 = l + pucch_pdu->start_symbol_index; + int re_offset = (12 * prb_offset[l]) + frame_parms->first_carrier_offset; if (re_offset>= frame_parms->ofdm_symbol_size) re_offset-=frame_parms->ofdm_symbol_size; //txptr = &txdataF[0][re_offset]; #ifdef DEBUG_NR_PUCCH_TX printf("\t [nr_generate_pucch0] symbol %d PRB %d (%u)\n",l,prb_offset[l],re_offset); -#endif +#endif + c16_t *txdataFptr = txdataF[0] + l2 * frame_parms->ofdm_symbol_size; + const int32_t amp = amp16; for (int n=0; n<12; n++) { - - txdataF[0][(l2*frame_parms->ofdm_symbol_size) + re_offset].r = (int16_t)(((int32_t)(amp) * x_n_re[l][n])>>15); - txdataF[0][(l2*frame_parms->ofdm_symbol_size) + re_offset].i = (int16_t)(((int32_t)(amp) * x_n_im[l][n])>>15); - //((int16_t *)txptr[0][re_offset])[0] = (int16_t)((int32_t)amp * x_n_re[(12*l)+n])>>15; - //((int16_t *)txptr[0][re_offset])[1] = (int16_t)((int32_t)amp * x_n_im[(12*l)+n])>>15; - //txptr[re_offset] = (x_n_re[(12*l)+n]<<16) + x_n_im[(12*l)+n]; + const c16_t angle = {lround(32767 * cos(alpha * n)), lround(32767 * sin(alpha * n))}; + const c16_t table = {table_5_2_2_2_2_Re[u[l]][n], table_5_2_2_2_2_Im[u[l]][n]}; + txdataFptr[re_offset] = c16mulRealShift(c16mulShift(angle, table, 15), amp, 15); #ifdef DEBUG_NR_PUCCH_TX - printf("\t [nr_generate_pucch0] mapping to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \ttxptr(%u)=(x_n(l=%d,n=%d)=(%d,%d))\n", - amp, frame_parms->ofdm_symbol_size, frame_parms->N_RB_DL, frame_parms->first_carrier_offset, (l2 * frame_parms->ofdm_symbol_size) + re_offset, - l2, n, txdataF[0][(l2*frame_parms->ofdm_symbol_size) + re_offset].r, - txdataF[0][(l2*frame_parms->ofdm_symbol_size) + re_offset].i); + printf( + "\t [nr_generate_pucch0] mapping to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d " + "\ttxptr(%u)=(x_n(l=%d,n=%d)=(%d,%d))\n", + amp, + frame_parms->ofdm_symbol_size, + frame_parms->N_RB_DL, + frame_parms->first_carrier_offset, + (l2 * frame_parms->ofdm_symbol_size) + re_offset, + l2, + n, + txdataFptr[re_offset].r, + txdataFptr[re_offset].i); #endif re_offset++; if (re_offset>= frame_parms->ofdm_symbol_size) @@ -172,7 +158,7 @@ void nr_generate_pucch0(const PHY_VARS_NR_UE *ue, void nr_generate_pucch1(const PHY_VARS_NR_UE *ue, c16_t **txdataF, const NR_DL_FRAME_PARMS *frame_parms, - const int16_t amp, + const int16_t amp16, const int nr_slot_tx, const fapi_nr_ul_config_pucch_pdu *pucch_pdu) { @@ -192,37 +178,20 @@ void nr_generate_pucch1(const PHY_VARS_NR_UE *ue, * */ // complex-valued symbol d_re, d_im containing complex-valued symbol d(0): - int16_t d_re = 0, d_im = 0; - + c16_t d = {0}; + const int32_t amp = amp16; + const int16_t baseVal = (amp * ONE_OVER_SQRT2) >> 15; + const c16_t qpskSymbols[4] = {{baseVal, baseVal}, {baseVal, -baseVal}, {-baseVal, baseVal}, {-baseVal, -baseVal}}; if (pucch_pdu->n_bit == 1) { // using BPSK if M_bit=1 according to TC 38.211 Subclause 5.1.2 - d_re = (payload&1)==0 ? (int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15) : -(int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - d_im = (payload&1)==0 ? (int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15) : -(int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); + d = (payload & 1) == 0 ? qpskSymbols[0] : qpskSymbols[3]; } if (pucch_pdu->n_bit == 2) { // using QPSK if M_bit=2 according to TC 38.211 Subclause 5.1.2 - if (((payload&1)==0) && (((payload>>1)&1)==0)) { - d_re = (int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); // 32767/sqrt(2) = 23170 (ONE_OVER_SQRT2) - d_im = (int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - } - - if (((payload&1)==0) && (((payload>>1)&1)==1)) { - d_re = (int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - d_im = -(int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - } - - if (((payload&1)==1) && (((payload>>1)&1)==0)) { - d_re = -(int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - d_im = (int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - } - - if (((payload&1)==1) && (((payload>>1)&1)==1)) { - d_re = -(int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - d_im = -(int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - } + int tmp = ((payload & 1) << 1) + ((payload >> 1) & 1); + d = qpskSymbols[tmp]; } -// printf("d_re=%d\td_im=%d\n",(int)d_re,(int)d_im); #ifdef DEBUG_NR_PUCCH_TX - printf("\t [nr_generate_pucch1] sequence modulation: payload=%lx \tde_re=%d \tde_im=%d\n",payload,d_re,d_im); + printf("\t [nr_generate_pucch1] sequence modulation: payload=%lx \tde_re=%d \tde_im=%d\n", payload, d.r, d.i); #endif /* * Defining cyclic shift hopping TS 38.211 Subclause 6.3.2.2.2 @@ -265,11 +234,11 @@ void nr_generate_pucch1(const PHY_VARS_NR_UE *ue, uint32_t re_offset=0; int i=0; #define MAX_SIZE_Z 168 // this value has to be calculated from mprime*12*table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_noHop[pucch_symbol_length]+m*12+n - int16_t z_re[MAX_SIZE_Z],z_im[MAX_SIZE_Z]; - int16_t z_dmrs_re[MAX_SIZE_Z],z_dmrs_im[MAX_SIZE_Z]; + c16_t z[MAX_SIZE_Z]; + c16_t z_dmrs[MAX_SIZE_Z]; // lprime is the index of the OFDM symbol in the slot that corresponds to the first OFDM symbol of the PUCCH transmission in the slot given by [5, TS 38.213] - uint8_t lprime = startingSymbolIndex; + int lprime = startingSymbolIndex; for (int l = 0; l < nrofSymbols; l++) { #ifdef DEBUG_NR_PUCCH_TX @@ -277,7 +246,7 @@ void nr_generate_pucch1(const PHY_VARS_NR_UE *ue, l,lprime); #endif // y_n contains the complex value d multiplied by the sequence r_u_v - int16_t y_n_re[12],y_n_im[12]; + c16_t y_n[12]; if ((intraSlotFrequencyHopping == 1) && (l >= (int)floor(nrofSymbols / 2))) n_hop = 1; // n_hop = 1 for second hop @@ -294,28 +263,27 @@ void nr_generate_pucch1(const PHY_VARS_NR_UE *ue, // r_u_v_alpha_delta_re and r_u_v_alpha_delta_im tables containing the sequence y(n) for the PUCCH, when they are multiplied by d(0) // r_u_v_alpha_delta_dmrs_re and r_u_v_alpha_delta_dmrs_im tables containing the sequence for the DM-RS. - int16_t r_u_v_alpha_delta_re[12], r_u_v_alpha_delta_im[12], r_u_v_alpha_delta_dmrs_re[12], r_u_v_alpha_delta_dmrs_im[12]; + c16_t r_u_v_alpha_delta[12], r_u_v_alpha_delta_dmrs[12]; for (int n = 0; n < 12; n++) { - r_u_v_alpha_delta_re[n] = (int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15) - - (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15))); // Re part of base sequence shifted by alpha - r_u_v_alpha_delta_im[n] = (int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15) - + (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15))); // Im part of base sequence shifted by alpha - r_u_v_alpha_delta_dmrs_re[n] = (int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15) - - (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15))); // Re part of DMRS base sequence shifted by alpha - r_u_v_alpha_delta_dmrs_im[n] = (int16_t)(((((int32_t)(round(32767*cos(alpha*n))) * table_5_2_2_2_2_Im[u][n])>>15) - + (((int32_t)(round(32767*sin(alpha*n))) * table_5_2_2_2_2_Re[u][n])>>15))); // Im part of DMRS base sequence shifted by alpha - r_u_v_alpha_delta_dmrs_re[n] = (int16_t)(((int32_t)(amp*r_u_v_alpha_delta_dmrs_re[n]))>>15); - r_u_v_alpha_delta_dmrs_im[n] = (int16_t)(((int32_t)(amp*r_u_v_alpha_delta_dmrs_im[n]))>>15); -// printf("symbol=%d\tr_u_v_re=%d\tr_u_v_im=%d\n",l,r_u_v_alpha_delta_re[n],r_u_v_alpha_delta_im[n]); + c16_t angle = {lround(32767 * cos(alpha * n)), lround(32767 * sin(alpha * n))}; + c16_t table = {table_5_2_2_2_2_Re[u][n], table_5_2_2_2_2_Im[u][n]}; + r_u_v_alpha_delta[n] = c16mulShift(angle, table, 15); + r_u_v_alpha_delta_dmrs[n] = c16mulRealShift(r_u_v_alpha_delta[n], amp, 15); // PUCCH sequence = DM-RS sequence multiplied by d(0) - y_n_re[n] = (int16_t)(((((int32_t)(r_u_v_alpha_delta_re[n])*d_re)>>15) - - (((int32_t)(r_u_v_alpha_delta_im[n])*d_im)>>15))); // Re part of y(n) - y_n_im[n] = (int16_t)(((((int32_t)(r_u_v_alpha_delta_re[n])*d_im)>>15) - + (((int32_t)(r_u_v_alpha_delta_im[n])*d_re)>>15))); // Im part of y(n) -// printf("symbol=%d\tr_u_v_dmrs_re=%d\tr_u_v_dmrs_im=%d\n",l,r_u_v_alpha_delta_dmrs_re[n],r_u_v_alpha_delta_dmrs_im[n]); + y_n[n] = c16mulShift(r_u_v_alpha_delta[n], d, 15); #ifdef DEBUG_NR_PUCCH_TX - printf("\t [nr_generate_pucch1] sequence generation \tu=%d \tv=%d \talpha=%lf \tr_u_v_alpha_delta[n=%d]=(%d,%d) \ty_n[n=%d]=(%d,%d)\n", - u,v,alpha,n,r_u_v_alpha_delta_re[n],r_u_v_alpha_delta_im[n],n,y_n_re[n],y_n_im[n]); + printf( + "\t [nr_generate_pucch1] sequence generation \tu=%d \tv=%d \talpha=%lf \tr_u_v_alpha_delta[n=%d]=(%d,%d) " + "\ty_n[n=%d]=(%d,%d)\n", + u, + v, + alpha, + n, + r_u_v_alpha_delta[n].r, + r_u_v_alpha_delta[n].i, + n, + y_n[n].r, + y_n[n].i); #endif } @@ -333,16 +301,13 @@ void nr_generate_pucch1(const PHY_VARS_NR_UE *ue, // the index of the orthogonal cover code is from a set determined as described in [4, TS 38.211] // and is indicated by higher layer parameter PUCCH-F1-time-domain-OCC // In the PUCCH_Config IE, the PUCCH-format1, timeDomainOCC field - uint8_t w_index = timeDomainOCC; - // N_SF_mprime_PUCCH_1 contains N_SF_mprime from table 6.3.2.4.1-1 (depending on number of PUCCH symbols nrofSymbols, mprime and intra-slot hopping enabled/disabled) - uint8_t N_SF_mprime_PUCCH_1; - // N_SF_mprime_PUCCH_1 contains N_SF_mprime from table 6.4.1.3.1.1-1 (depending on number of PUCCH symbols nrofSymbols, mprime and intra-slot hopping enabled/disabled) - uint8_t N_SF_mprime_PUCCH_DMRS_1; - // N_SF_mprime_PUCCH_1 contains N_SF_mprime from table 6.3.2.4.1-1 (depending on number of PUCCH symbols nrofSymbols, mprime=0 and intra-slot hopping enabled/disabled) - uint8_t N_SF_mprime0_PUCCH_1; - // N_SF_mprime_PUCCH_1 contains N_SF_mprime from table 6.4.1.3.1.1-1 (depending on number of PUCCH symbols nrofSymbols, mprime=0 and intra-slot hopping enabled/disabled) - uint8_t N_SF_mprime0_PUCCH_DMRS_1; - // mprime is 0 if no intra-slot hopping / mprime is {0,1} if intra-slot hopping + const uint8_t w_index = timeDomainOCC; + // N_SF_mprime_PUCCH_1 contains N_SF_mprime from table 6.3.2.4.1-1 (depending on number of PUCCH symbols nrofSymbols, mprime + // and intra-slot hopping enabled/disabled) N_SF_mprime_PUCCH_1 contains N_SF_mprime from table 6.4.1.3.1.1-1 (depending on + // number of PUCCH symbols nrofSymbols, mprime and intra-slot hopping enabled/disabled) N_SF_mprime_PUCCH_1 contains N_SF_mprime + // from table 6.3.2.4.1-1 (depending on number of PUCCH symbols nrofSymbols, mprime=0 and intra-slot hopping enabled/disabled) + // N_SF_mprime_PUCCH_1 contains N_SF_mprime from table 6.4.1.3.1.1-1 (depending on number of PUCCH symbols nrofSymbols, mprime=0 + // and intra-slot hopping enabled/disabled) mprime is 0 if no intra-slot hopping / mprime is {0,1} if intra-slot hopping uint8_t mprime = 0; if (intraSlotFrequencyHopping == 0) { // intra-slot hopping disabled @@ -350,46 +315,74 @@ void nr_generate_pucch1(const PHY_VARS_NR_UE *ue, printf("\t [nr_generate_pucch1] block-wise spread with the orthogonal sequence wi(m) if intraSlotFrequencyHopping = %d, intra-slot hopping disabled\n", intraSlotFrequencyHopping); #endif - N_SF_mprime_PUCCH_1 = table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_noHop[nrofSymbols-1]; // only if intra-slot hopping not enabled (PUCCH) - N_SF_mprime_PUCCH_DMRS_1 = table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_noHop[nrofSymbols-1]; // only if intra-slot hopping not enabled (DM-RS) - N_SF_mprime0_PUCCH_1 = table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_noHop[nrofSymbols-1]; // only if intra-slot hopping not enabled mprime = 0 (PUCCH) - N_SF_mprime0_PUCCH_DMRS_1 = table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_noHop[nrofSymbols-1]; // only if intra-slot hopping not enabled mprime = 0 (DM-RS) + int N_SF_mprime_PUCCH_1 = + table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_noHop[nrofSymbols - 1]; // only if intra-slot hopping not enabled (PUCCH) + int N_SF_mprime_PUCCH_DMRS_1 = + table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_noHop[nrofSymbols - 1]; // only if intra-slot hopping not enabled (DM-RS) + int N_SF_mprime0_PUCCH_1 = + table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_noHop[nrofSymbols - 1]; // only if intra-slot hopping not enabled mprime = 0 (PUCCH) + int N_SF_mprime0_PUCCH_DMRS_1 = + table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_noHop[nrofSymbols + - 1]; // only if intra-slot hopping not enabled mprime = 0 (DM-RS) #ifdef DEBUG_NR_PUCCH_TX printf("\t [nr_generate_pucch1] w_index = %d, N_SF_mprime_PUCCH_1 = %d, N_SF_mprime_PUCCH_DMRS_1 = %d, N_SF_mprime0_PUCCH_1 = %d, N_SF_mprime0_PUCCH_DMRS_1 = %d\n", w_index, N_SF_mprime_PUCCH_1,N_SF_mprime_PUCCH_DMRS_1,N_SF_mprime0_PUCCH_1,N_SF_mprime0_PUCCH_DMRS_1); #endif for (int m=0; m < N_SF_mprime_PUCCH_1; m++) { + c16_t *zPtr = z + mprime * 12 * N_SF_mprime0_PUCCH_1 + m * 12; + c16_t table = {table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m], + table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m]}; for (int n=0; n<12 ; n++) { - z_re[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n] = (int16_t)((((int32_t)(table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m])*y_n_re[n])>>15) - - (((int32_t)(table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m])*y_n_im[n])>>15)); - z_im[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n] = (int16_t)((((int32_t)(table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m])*y_n_im[n])>>15) - + (((int32_t)(table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m])*y_n_re[n])>>15)); + zPtr[n] = c16mulShift(table, y_n[n], 15); #ifdef DEBUG_NR_PUCCH_TX - printf("\t [nr_generate_pucch1] block-wise spread with wi(m) (mprime=%d, m=%d, n=%d) z[%d] = ((%d * %d - %d * %d), (%d * %d + %d * %d)) = (%d,%d)\n", - mprime, m, n, (mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n, - table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],y_n_re[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],y_n_im[n], - table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],y_n_im[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],y_n_re[n], - z_re[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_im[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); + printf( + "\t [nr_generate_pucch1] block-wise spread with wi(m) (mprime=%d, m=%d, n=%d) z[%d] = ((%d * %d - %d * %d), (%d * %d " + "+ %d * %d)) = (%d,%d)\n", + mprime, + m, + n, + (mprime * 12 * N_SF_mprime0_PUCCH_1) + (m * 12) + n, + table.r, + y_n[n].r, + table.i, + y_n[n].i, + table.r, + y_n[n].i, + table.i, + y_n[n].r, + zPtr[n].r, + zPtr[n].i); #endif } } for (int m=0; m < N_SF_mprime_PUCCH_DMRS_1; m++) { + c16_t *zDmrsPtr = z_dmrs + mprime * 12 * N_SF_mprime0_PUCCH_DMRS_1 + m * 12; + c16_t table = {table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_DMRS_1][w_index][m], + table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_DMRS_1][w_index][m]}; for (int n=0; n<12 ; n++) { - z_dmrs_re[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n] = (int16_t)((((int32_t)(table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_DMRS_1][w_index][m])*r_u_v_alpha_delta_dmrs_re[n])>>15) - - (((int32_t)(table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_DMRS_1][w_index][m])*r_u_v_alpha_delta_dmrs_im[n])>>15)); - z_dmrs_im[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n] = (int16_t)((((int32_t)(table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_DMRS_1][w_index][m])*r_u_v_alpha_delta_dmrs_im[n])>>15) - + (((int32_t)(table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_DMRS_1][w_index][m])*r_u_v_alpha_delta_dmrs_re[n])>>15)); + zDmrsPtr[n] = c16mulShift(table, r_u_v_alpha_delta_dmrs[n], 15); #ifdef DEBUG_NR_PUCCH_TX - printf("\t [nr_generate_pucch1] block-wise spread with wi(m) (mprime=%d, m=%d, n=%d) z[%d] = ((%d * %d - %d * %d), (%d * %d + %d * %d)) = (%d,%d)\n", - mprime, m, n, (mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n, - table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_re[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_im[n], - table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_im[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_re[n], - z_dmrs_re[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_dmrs_im[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); + printf( + "\t [nr_generate_pucch1] block-wise spread with wi(m) (mprime=%d, m=%d, n=%d) z[%d] = ((%d * %d - %d * %d), (%d * %d " + "+ %d * %d)) = (%d,%d)\n", + mprime, + m, + n, + (mprime * 12 * N_SF_mprime0_PUCCH_1) + (m * 12) + n, + table.r, + r_u_v_alpha_delta_dmrs[n].r, + table.i, + r_u_v_alpha_delta_dmrs[n].i, + table.r, + r_u_v_alpha_delta_dmrs[n].i, + table.i, + r_u_v_alpha_delta_dmrs[n].r, + zDmrsPtr[n].r, + zDmrsPtr[n].i); #endif -// printf("gNB entering l=%d\tdmrs_re=%d\tdmrs_im=%d\n",l,z_dmrs_re[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n],z_dmrs_re[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n]); - } + } } } @@ -398,10 +391,14 @@ void nr_generate_pucch1(const PHY_VARS_NR_UE *ue, printf("\t [nr_generate_pucch1] block-wise spread with the orthogonal sequence wi(m) if intraSlotFrequencyHopping = %d, intra-slot hopping enabled\n", intraSlotFrequencyHopping); #endif - N_SF_mprime_PUCCH_1 = table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_m0Hop[nrofSymbols-1]; // only if intra-slot hopping enabled mprime = 0 (PUCCH) - N_SF_mprime_PUCCH_DMRS_1 = table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_m0Hop[nrofSymbols-1]; // only if intra-slot hopping enabled mprime = 0 (DM-RS) - N_SF_mprime0_PUCCH_1 = table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_m0Hop[nrofSymbols-1]; // only if intra-slot hopping enabled mprime = 0 (PUCCH) - N_SF_mprime0_PUCCH_DMRS_1 = table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_m0Hop[nrofSymbols-1]; // only if intra-slot hopping enabled mprime = 0 (DM-RS) + int N_SF_mprime_PUCCH_1 = + table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_m0Hop[nrofSymbols - 1]; // only if intra-slot hopping enabled mprime = 0 (PUCCH) + int N_SF_mprime_PUCCH_DMRS_1 = + table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_m0Hop[nrofSymbols - 1]; // only if intra-slot hopping enabled mprime = 0 (DM-RS) + int N_SF_mprime0_PUCCH_1 = + table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_m0Hop[nrofSymbols - 1]; // only if intra-slot hopping enabled mprime = 0 (PUCCH) + int N_SF_mprime0_PUCCH_DMRS_1 = + table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_m0Hop[nrofSymbols - 1]; // only if intra-slot hopping enabled mprime = 0 (DM-RS) #ifdef DEBUG_NR_PUCCH_TX printf("\t [nr_generate_pucch1] w_index = %d, N_SF_mprime_PUCCH_1 = %d, N_SF_mprime_PUCCH_DMRS_1 = %d, N_SF_mprime0_PUCCH_1 = %d, N_SF_mprime0_PUCCH_DMRS_1 = %d\n", w_index, N_SF_mprime_PUCCH_1,N_SF_mprime_PUCCH_DMRS_1,N_SF_mprime0_PUCCH_1,N_SF_mprime0_PUCCH_DMRS_1); @@ -409,38 +406,23 @@ void nr_generate_pucch1(const PHY_VARS_NR_UE *ue, for (mprime = 0; mprime<2; mprime++) { // mprime can get values {0,1} for (int m=0; m < N_SF_mprime_PUCCH_1; m++) { - for (int n=0; n<12 ; n++) { - z_re[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n] = (int16_t)((((int32_t)(table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m])*y_n_re[n])>>15) - - (((int32_t)(table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m])*y_n_im[n])>>15)); - z_im[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n] = (int16_t)((((int32_t)(table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m])*y_n_im[n])>>15) - + (((int32_t)(table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m])*y_n_re[n])>>15)); -#ifdef DEBUG_NR_PUCCH_TX - printf("\t [nr_generate_pucch1] block-wise spread with wi(m) (mprime=%d, m=%d, n=%d) z[%d] = ((%d * %d - %d * %d), (%d * %d + %d * %d)) = (%d,%d)\n", - mprime, m, n, (mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n, - table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],y_n_re[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],y_n_im[n], - table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],y_n_im[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],y_n_re[n], - z_re[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_im[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); -#endif - } + c16_t *zPtr = z + mprime * 12 * N_SF_mprime0_PUCCH_1 + m * 12; + c16_t table = {table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m], + table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m]}; + for (int n = 0; n < 12; n++) + zPtr[n] = c16mulShift(table, y_n[n], 15); } for (int m=0; m < N_SF_mprime_PUCCH_DMRS_1; m++) { - for (int n=0; n<12 ; n++) { - z_dmrs_re[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n] = (int16_t)((((int32_t)(table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_DMRS_1][w_index][m])*r_u_v_alpha_delta_dmrs_re[n])>>15) - - (((int32_t)(table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_DMRS_1][w_index][m])*r_u_v_alpha_delta_dmrs_im[n])>>15)); - z_dmrs_im[(mprime*12*N_SF_mprime0_PUCCH_DMRS_1)+(m*12)+n] = (int16_t)((((int32_t)(table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_DMRS_1][w_index][m])*r_u_v_alpha_delta_dmrs_im[n])>>15) - + (((int32_t)(table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_DMRS_1][w_index][m])*r_u_v_alpha_delta_dmrs_re[n])>>15)); -#ifdef DEBUG_NR_PUCCH_TX - printf("\t [nr_generate_pucch1] block-wise spread with wi(m) (mprime=%d, m=%d, n=%d) z[%d] = ((%d * %d - %d * %d), (%d * %d + %d * %d)) = (%d,%d)\n", - mprime, m, n, (mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n, - table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_re[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_im[n], - table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_im[n],table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_1][w_index][m],r_u_v_alpha_delta_dmrs_re[n], - z_dmrs_re[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n],z_dmrs_im[(mprime*12*N_SF_mprime0_PUCCH_1)+(m*12)+n]); -#endif - } + c16_t *zDmrsPtr = z_dmrs + mprime * 12 * N_SF_mprime0_PUCCH_DMRS_1 + m * 12; + c16_t table = {table_6_3_2_4_1_2_Wi_Re[N_SF_mprime_PUCCH_DMRS_1][w_index][m], + table_6_3_2_4_1_2_Wi_Im[N_SF_mprime_PUCCH_DMRS_1][w_index][m]}; + for (int n = 0; n < 12; n++) + zDmrsPtr[n] = c16mulShift(table, r_u_v_alpha_delta_dmrs[n], 15); } - N_SF_mprime_PUCCH_1 = table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_m1Hop[nrofSymbols-1]; // only if intra-slot hopping enabled mprime = 1 (PUCCH) + N_SF_mprime_PUCCH_1 = + table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_m1Hop[nrofSymbols - 1]; // only if intra-slot hopping enabled mprime = 1 (PUCCH) N_SF_mprime_PUCCH_DMRS_1 = table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_m1Hop[nrofSymbols-1]; // only if intra-slot hopping enabled mprime = 1 (DM-RS) } } @@ -476,8 +458,7 @@ void nr_generate_pucch1(const PHY_VARS_NR_UE *ue, } if (l%2 == 1) { // mapping PUCCH according to TS38.211 subclause 6.4.1.3.1 - txdataF[0][re_offset].r = z_re[i+n]; - txdataF[0][re_offset].i = z_im[i+n]; + txdataF[0][re_offset] = z[i + n]; #ifdef DEBUG_NR_PUCCH_TX printf("\t [nr_generate_pucch1] mapping PUCCH to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \tz_pucch[%d]=txptr(%u)=(x_n(l=%d,n=%d)=(%d,%d))\n", amp, frame_parms->ofdm_symbol_size, frame_parms->N_RB_DL, frame_parms->first_carrier_offset, i + n, re_offset, @@ -486,8 +467,7 @@ void nr_generate_pucch1(const PHY_VARS_NR_UE *ue, } if (l % 2 == 0) { // mapping DM-RS signal according to TS38.211 subclause 6.4.1.3.1 - txdataF[0][re_offset].r = z_dmrs_re[i+n]; - txdataF[0][re_offset].i = z_dmrs_im[i+n]; + txdataF[0][re_offset] = z_dmrs[i + n]; #ifdef DEBUG_NR_PUCCH_TX printf("\t [nr_generate_pucch1] mapping DM-RS to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \tz_dm-rs[%d]=txptr(%u)=(x_n(l=%d,n=%d)=(%d,%d))\n", amp, frame_parms->ofdm_symbol_size, frame_parms->N_RB_DL, frame_parms->first_carrier_offset, i+n, re_offset, @@ -504,7 +484,6 @@ void nr_generate_pucch1(const PHY_VARS_NR_UE *ue, } } -static inline void nr_pucch2_3_4_scrambling(uint16_t M_bit,uint16_t rnti,uint16_t n_id,uint64_t *B64,uint8_t *btilde) __attribute__((always_inline)); static inline void nr_pucch2_3_4_scrambling(uint16_t M_bit,uint16_t rnti,uint16_t n_id,uint64_t *B64,uint8_t *btilde) { uint32_t x1 = 0, x2 = 0, s = 0; int i; @@ -632,7 +611,7 @@ static void nr_uci_encoding(uint64_t payload, if (A<=11) { // procedure in subclause 6.3.1.2.2 (UCI encoded by channel coding of small block lengths -> subclause 6.3.1.3.2) // CRC bits are not attached, and coding small block lengths (subclause 5.3.3) - uint64_t b0= encodeSmallBlock((uint16_t*)&payload,A); + uint64_t b0 = encodeSmallBlock(payload, A); // repetition for rate-matching up to 16 PRB b[0] = b0 | (b0<<32); b[1] = b[0]; @@ -658,7 +637,7 @@ static void nr_uci_encoding(uint64_t payload, void nr_generate_pucch2(const PHY_VARS_NR_UE *ue, c16_t **txdataF, const NR_DL_FRAME_PARMS *frame_parms, - const int16_t amp, + const int16_t amp16, const int nr_slot_tx, const fapi_nr_ul_config_pucch_pdu *pucch_pdu) { @@ -687,8 +666,8 @@ void nr_generate_pucch2(const PHY_VARS_NR_UE *ue, * n_id = {0,1,...,1023} equals the higher-layer parameter Data-scrambling-Identity if configured * n_id = N_ID_cell if higher layer parameter not configured */ - uint8_t *btilde = calloc(M_bit, sizeof(uint8_t)); - + uint8_t btilde[M_bit]; + memset(btilde, 0, sizeof(btilde)); // rnti is given by the C-RNTI uint16_t rnti=pucch_pdu->rnti; #ifdef DEBUG_NR_PUCCH_TX @@ -717,41 +696,31 @@ void nr_generate_pucch2(const PHY_VARS_NR_UE *ue, */ //#define ONE_OVER_SQRT2_S 23171 // 32767/sqrt(2) = 23170 (ONE_OVER_SQRT2) // complex-valued symbol d(0) - int16_t *d_re = calloc(M_bit, sizeof(int16_t)); - int16_t *d_im = calloc(M_bit, sizeof(int16_t)); + c16_t d[M_bit]; + memset(d, 0, sizeof(d)); uint16_t m_symbol = (M_bit%2==0) ? M_bit/2 : floor(M_bit/2)+1; - + const int32_t amp = amp16; + const int16_t baseVal = (amp * ONE_OVER_SQRT2) >> 15; + c16_t qpskSymbols[4] = {{baseVal, baseVal}, {baseVal, -baseVal}, {-baseVal, baseVal}, {-baseVal, -baseVal}}; for (int i=0; i < m_symbol; i++) { // QPSK modulation subclause 5.1.3 - if (((btilde[2*i]&1)==0) && ((btilde[(2*i)+1]&1)==0)) { - d_re[i] = (int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - d_im[i] = (int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - } - - if (((btilde[2*i]&1)==0) && ((btilde[(2*i)+1]&1)==1)) { - d_re[i] = (int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - d_im[i] = -(int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - } - - if (((btilde[2*i]&1)==1) && ((btilde[(2*i)+1]&1)==0)) { - d_re[i] = -(int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - d_im[i] = (int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - } - - if (((btilde[2*i]&1)==1) && ((btilde[(2*i)+1]&1)==1)) { - d_re[i] = -(int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - d_im[i] = -(int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - } + int tmp = (btilde[2 * i] & 1) * 2 + (btilde[(2 * i) + 1] & 1); + d[i] = qpskSymbols[tmp]; #ifdef DEBUG_NR_PUCCH_TX - printf("\t [nr_generate_pucch2] modulation of bit pair btilde(%d,%d), m_symbol=%d, d(%d)=(%d,%d)\n",(btilde[2*i]&1),(btilde[(2*i)+1]&1),m_symbol,i,d_re[i],d_im[i]); + printf("\t [nr_generate_pucch2] modulation of bit pair btilde(%d,%d), m_symbol=%d, d(%d)=(%d,%d)\n", + (btilde[2 * i] & 1), + (btilde[(2 * i) + 1] & 1), + m_symbol, + i, + d[i].r, + d[i].i); #endif } /* * Implementing TS 38.211 Subclause 6.3.2.5.3 Mapping to physical resources */ - //int32_t *txptr; - uint32_t re_offset=0; + // int32_t *txptr; uint32_t x1 = 0, x2 = 0, s = 0; int i=0; int m=0; @@ -773,24 +742,22 @@ void nr_generate_pucch2(const PHY_VARS_NR_UE *ue, m = 0; for (int rb=0; rbprb_size; rb++) { //startingPRB = startingPRB + rb; - if (((rb+startingPRB) < (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 0)) { // if number RBs in bandwidth is even and current PRB is lower band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*(rb+startingPRB)) + frame_parms->first_carrier_offset; - } - - if (((rb+startingPRB) >= (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 0)) { // if number RBs in bandwidth is even and current PRB is upper band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*((rb+startingPRB)-(frame_parms->N_RB_DL>>1))); - } - - if (((rb+startingPRB) < (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd and current PRB is lower band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*(rb+startingPRB)) + frame_parms->first_carrier_offset; - } - - if (((rb+startingPRB) > (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd and current PRB is upper band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*((rb+startingPRB)-(frame_parms->N_RB_DL>>1))) + 6; - } - - if (((rb+startingPRB) == (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd and current PRB contains DC - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*(rb+startingPRB)) + frame_parms->first_carrier_offset; + const bool nb_rb_is_even = frame_parms->N_RB_DL & 1; + const int halfRBs = frame_parms->N_RB_DL / 2; + const int baseRB = rb + startingPRB; + int re_offset = (l + startingSymbolIndex) * frame_parms->ofdm_symbol_size + 12 * baseRB; + if (nb_rb_is_even) { + if (baseRB < halfRBs) // if number RBs in bandwidth is even and current PRB is lower band + re_offset += frame_parms->first_carrier_offset; + else + re_offset -= halfRBs; + } else { + if (baseRB < halfRBs) // if number RBs in bandwidth is odd and current PRB is lower band + re_offset += frame_parms->first_carrier_offset; + else if (baseRB > halfRBs) // if number RBs in bandwidth is odd and current PRB is upper band + re_offset += -halfRBs + 6; + else + re_offset += frame_parms->first_carrier_offset; } //txptr = &txdataF[0][re_offset]; @@ -800,14 +767,13 @@ void nr_generate_pucch2(const PHY_VARS_NR_UE *ue, #endif for (int n=0; n<12; n++) { - if ((n==6) && ((rb+startingPRB) == (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { + if (n == 6 && baseRB == halfRBs && !nb_rb_is_even) { // if number RBs in bandwidth is odd and current PRB contains DC, we need to recalculate the offset when n=6 (for second half PRB) re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size); } if (n%3 != 1) { // mapping PUCCH according to TS38.211 subclause 6.3.2.5.3 - ((int16_t *)&txdataF[0][re_offset])[0] = d_re[i+k]; - ((int16_t *)&txdataF[0][re_offset])[1] = d_im[i+k]; + txdataF[0][re_offset] = d[i + k]; #ifdef DEBUG_NR_PUCCH_TX printf( "\t [nr_generate_pucch2] (n=%d,i=%d) mapping PUCCH to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d " @@ -822,15 +788,15 @@ void nr_generate_pucch2(const PHY_VARS_NR_UE *ue, re_offset, l, n, - ((int16_t *)&txdataF[0][re_offset])[0], - ((int16_t *)&txdataF[0][re_offset])[1]); + txdataF[0][re_offset].r, + txdataF[0][re_offset].i); #endif k++; } if (n%3 == 1) { // mapping DM-RS signal according to TS38.211 subclause 6.4.1.3.2 - ((int16_t *)&txdataF[0][re_offset])[0] = (int16_t)((int32_t)(amp*ONE_OVER_SQRT2*(1-(2*((uint8_t)((s>>(2*m))&1)))))>>15); - ((int16_t *)&txdataF[0][re_offset])[1] = (int16_t)((int32_t)(amp*ONE_OVER_SQRT2*(1-(2*((uint8_t)((s>>((2*m)+1))&1)))))>>15); + txdataF[0][re_offset].r = (int16_t)(baseVal * (1 - (2 * ((uint8_t)((s >> (2 * m)) & 1))))); + txdataF[0][re_offset].i = (int16_t)(baseVal * (1 - (2 * ((uint8_t)((s >> (2 * m + 1)) & 1))))); m++; #ifdef DEBUG_NR_PUCCH_TX printf( @@ -846,8 +812,8 @@ void nr_generate_pucch2(const PHY_VARS_NR_UE *ue, re_offset, l, n, - ((int16_t *)&txdataF[0][re_offset])[0], - ((int16_t *)&txdataF[0][re_offset])[1]); + txdataF[0][re_offset].r, + txdataF[0][re_offset].i); kk++; #endif } @@ -863,15 +829,12 @@ void nr_generate_pucch2(const PHY_VARS_NR_UE *ue, } } } - free(d_re); - free(d_im); - free(btilde); } //#if 0 void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, c16_t **txdataF, const NR_DL_FRAME_PARMS *frame_parms, - const int16_t amp, + const int16_t amp16, const int nr_slot_tx, const fapi_nr_ul_config_pucch_pdu *pucch_pdu) { @@ -902,7 +865,7 @@ void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, printf("\t [nr_generate_pucch3_4] intraSlotFrequencyHopping=%d \n",intraSlotFrequencyHopping); #endif } - + const int32_t amp = amp16; uint8_t nrofSymbols = pucch_pdu->nr_of_symbols; uint16_t nrofPRB = pucch_pdu->prb_size; uint16_t startingPRB = pucch_pdu->prb_start + pucch_pdu->bwp_start; @@ -912,11 +875,13 @@ void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, pucch_pdu->n_bit, pucch_pdu->format_type, is_pi_over_2_bpsk_enabled, - nrofSymbols,nrofPRB, + nrofSymbols, + nrofPRB, n_SF_PUCCH_s, intraSlotFrequencyHopping, add_dmrs, - &b[0],&M_bit); + b, + &M_bit); /* * Implementing TS 38.211 * Subclauses 6.3.2.6.1 Scrambling (PUCCH formats 3 and 4) @@ -929,7 +894,7 @@ void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, * n_id = {0,1,...,1023} equals the higher-layer parameter Data-scrambling-Identity if configured * n_id = N_ID_cell if higher layer parameter not configured */ - uint8_t *btilde = malloc(sizeof(int8_t)*M_bit); + uint8_t btilde[M_bit]; // rnti is given by the C-RNTI uint16_t rnti=pucch_pdu->rnti, n_id=0; #ifdef DEBUG_NR_PUCCH_TX @@ -946,35 +911,24 @@ void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, * Subclause 5.1.3 QPSK */ // complex-valued symbol d(0) - int16_t *d_re = malloc(sizeof(int16_t)*M_bit); - int16_t *d_im = malloc(sizeof(int16_t)*M_bit); + c16_t d[M_bit]; uint16_t m_symbol = (M_bit%2==0) ? M_bit/2 : floor(M_bit/2)+1; + const int16_t baseVal = (amp * ONE_OVER_SQRT2) >> 15; if (is_pi_over_2_bpsk_enabled == 0) { // using QPSK if PUCCH format 3,4 and pi/2-BPSK is not configured, according to subclause 6.3.2.6.2 + c16_t qpskSymbols[4] = {{baseVal, baseVal}, {-baseVal, baseVal}, {-baseVal, baseVal}, {-baseVal, -baseVal}}; for (int i=0; i < m_symbol; i++) { // QPSK modulation subclause 5.1.3 - if (((btilde[2*i]&1)==0) && ((btilde[(2*i)+1]&1)==0)) { - d_re[i] = (int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - d_im[i] = (int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - } - - if (((btilde[2*i]&1)==0) && ((btilde[(2*i)+1]&1)==1)) { - d_re[i] = (int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - d_im[i] = -(int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - } - - if (((btilde[2*i]&1)==1) && ((btilde[(2*i)+1]&1)==0)) { - d_re[i] = -(int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - d_im[i] = (int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - } - - if (((btilde[2*i]&1)==1) && ((btilde[(2*i)+1]&1)==1)) { - d_re[i] = -(int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - d_im[i] = -(int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - } - + int tmp = (btilde[2 * i] & 1) * 2 + (btilde[(2 * i) + 1] & 1); + d[i] = qpskSymbols[tmp]; #ifdef DEBUG_NR_PUCCH_TX - printf("\t [nr_generate_pucch3_4] modulation QPSK of bit pair btilde(%d,%d), m_symbol=%d, d(%d)=(%d,%d)\n",(btilde[2*i]&1),(btilde[(2*i)+1]&1),m_symbol,i,d_re[i],d_im[i]); + printf("\t [nr_generate_pucch3_4] modulation QPSK of bit pair btilde(%d,%d), m_symbol=%d, d(%d)=(%d,%d)\n", + (btilde[2 * i] & 1), + (btilde[(2 * i) + 1] & 1), + m_symbol, + i, + d[i].r, + d[i].i); #endif } } @@ -982,30 +936,17 @@ void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, if (is_pi_over_2_bpsk_enabled == 1) { // using PI/2-BPSK if PUCCH format 3,4 and pi/2-BPSK is configured, according to subclause 6.3.2.6.2 m_symbol = M_bit; - + c16_t qpskSymbols[4] = {{baseVal, baseVal}, {-baseVal, baseVal}, {-baseVal, -baseVal}, {baseVal, -baseVal}}; for (int i=0; i>15); - d_im[i] = (int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - } - - if (((btilde[i]&1)==0) && (i%2 == 1)) { - d_re[i] = -(int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - d_im[i] = (int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - } - - if (((btilde[i]&1)==1) && (i%2 == 0)) { - d_re[i] = -(int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - d_im[i] = -(int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - } - - if (((btilde[i]&1)==1) && (i%2 == 1)) { - d_re[i] = (int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - d_im[i] = -(int16_t)(((int32_t)amp*ONE_OVER_SQRT2)>>15); - } - + int tmp = (btilde[i] & 1) * 2 + (i & 1); + d[i] = qpskSymbols[tmp]; #ifdef DEBUG_NR_PUCCH_TX - printf("\t [nr_generate_pucch3_4] modulation PI/2-BPSK of bit btilde(%d), m_symbol=%d, d(%d)=(%d,%d)\n",(btilde[i]&1),m_symbol,i,d_re[i],d_im[i]); + printf("\t [nr_generate_pucch3_4] modulation PI/2-BPSK of bit btilde(%d), m_symbol=%d, d(%d)=(%d,%d)\n", + (btilde[i] & 1), + m_symbol, + i, + d[i].r, + d[i].i); #endif } } @@ -1020,33 +961,27 @@ void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, // number of symbols, provided by higher layers parameters PUCCH-F0-F2-number-of-symbols or PUCCH-F1-F3-F4-number-of-symbols // uint8_t nrofSymbols; // complex-valued symbol d(0) - int16_t *y_n_re = malloc(sizeof(int16_t)*4*M_bit); // 4 is the maximum number n_SF_PUCCH_s, so is the maximunm size of y_n - int16_t *y_n_im = malloc(sizeof(int16_t)*4*M_bit); + c16_t y_n[4 * M_bit]; // 4 is the maximum number n_SF_PUCCH_s, so is the maximunm size of y_n // Re part orthogonal sequences w_n(k) for PUCCH format 4 when N_SF_PUCCH4 = 2 (Table 6.3.2.6.3-1) // k={0,..11} n={0,1,2,3} // parameter PUCCH-F4-preDFT-OCC-index set of {0,1,2,3} -> n - uint16_t table_6_3_2_6_3_1_Wn_Re[2][12] = {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1, 1,-1,-1,-1,-1,-1,-1} - }; + const uint16_t table_6_3_2_6_3_1_Wn_Re[2][12] = {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1}}; // Im part orthogonal sequences w_n(k) for PUCCH format 4 when N_SF_PUCCH4 = 2 (Table 6.3.2.6.3-1) // k={0,..11} n={0,1} - uint16_t table_6_3_2_6_3_1_Wn_Im[2][12] = {{0,0,0,0,0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0,0,0,0,0} - }; + const uint16_t table_6_3_2_6_3_1_Wn_Im[2][12] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; // Re part orthogonal sequences w_n(k) for PUCCH format 4 when N_SF_PUCCH4 = 4 (Table 6.3.2.6.3-2) // k={0,..11} n={0,1,2.3} - uint16_t table_6_3_2_6_3_2_Wn_Re[4][12] = {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, - {1, 1, 1, 0, 0, 0,-1,-1,-1, 0, 0, 0}, - {1, 1, 1,-1,-1,-1, 1, 1, 1,-1,-1,-1}, - {1, 1, 1, 0, 0, 0,-1,-1,-1, 0, 0, 0} - }; + const uint16_t table_6_3_2_6_3_2_Wn_Re[4][12] = {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 0, 0, 0, -1, -1, -1, 0, 0, 0}, + {1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1, -1}, + {1, 1, 1, 0, 0, 0, -1, -1, -1, 0, 0, 0}}; // Im part orthogonal sequences w_n(k) for PUCCH format 4 when N_SF_PUCCH4 = 4 (Table 6.3.2.6.3-2) // k={0,..11} n={0,1,2,3} - uint16_t table_6_3_2_6_3_2_Wn_Im[4][12] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0,-1,-1,-1, 0, 0, 0, 1, 1, 1}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 1, 1, 1, 0, 0, 0,-1,-1,-1} - }; + const uint16_t table_6_3_2_6_3_2_Wn_Im[4][12] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, -1, -1, -1, 0, 0, 0, 1, 1, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 1, 1, 1, 0, 0, 0, -1, -1, -1}}; uint8_t occ_Index = pucch_pdu->pre_dft_occ_idx; // higher layer parameter occ-Index @@ -1054,12 +989,17 @@ void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, if (pucch_pdu->format_type == 3) { // no block-wise spreading for format 3 for (int l=0; l < floor(m_symbol/(12*nrofPRB)); l++) { - for (int k=0; k < (12*nrofPRB); k++) { - y_n_re[l*(12*nrofPRB)+k] = d_re[l*(12*nrofPRB)+k]; - y_n_im[l*(12*nrofPRB)+k] = d_im[l*(12*nrofPRB)+k]; + for (int k = l * 12 * nrofPRB; k < (l + 1) * 12 * nrofPRB; k++) { + y_n[k] = d[k]; #ifdef DEBUG_NR_PUCCH_TX - printf("\t [nr_generate_pucch3_4] block-wise spreading for format 3 (no block-wise spreading): (l,k)=(%d,%d)\ty_n(%d) = \t(d_re=%d, d_im=%d)\n", - l,k,l*(12*nrofPRB)+k,d_re[l*(12*nrofPRB)+k],d_im[l*(12*nrofPRB)+k]); + printf( + "\t [nr_generate_pucch3_4] block-wise spreading for format 3 (no block-wise spreading): (l,k)=(%d,%d)\ty_n(%d) = " + "\t(d_re=%d, d_im=%d)\n", + l, + k, + k, + d[k].r, + d[k].i); #endif } } @@ -1070,29 +1010,37 @@ void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, for (int l=0; l < floor((n_SF_PUCCH_s*m_symbol)/(12*nrofPRB)); l++) { for (int k=0; k < (12*nrofPRB); k++) { + c16_t dVal = d[l * (12 * nrofPRB / n_SF_PUCCH_s) + k % (12 * nrofPRB / n_SF_PUCCH_s)]; + c16_t *yPtr = y_n + l * 12 * nrofPRB + k; if (n_SF_PUCCH_s == 2) { - y_n_re[l*(12*nrofPRB)+k] = (uint16_t)(((uint32_t)d_re[l*(12*nrofPRB/n_SF_PUCCH_s)+k%(12*nrofPRB/n_SF_PUCCH_s)] * table_6_3_2_6_3_1_Wn_Re[occ_Index][k]) - - ((uint32_t)d_im[l*(12*nrofPRB/n_SF_PUCCH_s)+k%(12*nrofPRB/n_SF_PUCCH_s)] * table_6_3_2_6_3_1_Wn_Im[occ_Index][k])); - y_n_im[l*(12*nrofPRB)+k] = (uint16_t)(((uint32_t)d_im[l*(12*nrofPRB/n_SF_PUCCH_s)+k%(12*nrofPRB/n_SF_PUCCH_s)] * table_6_3_2_6_3_1_Wn_Re[occ_Index][k]) - + ((uint32_t)d_re[l*(12*nrofPRB/n_SF_PUCCH_s)+k%(12*nrofPRB/n_SF_PUCCH_s)] * table_6_3_2_6_3_1_Wn_Im[occ_Index][k])); + c16_t table = {table_6_3_2_6_3_1_Wn_Re[occ_Index][k], table_6_3_2_6_3_1_Wn_Im[occ_Index][k]}; + *yPtr = c16mulShift(table, dVal, 15); #ifdef DEBUG_NR_PUCCH_TX - printf("\t [nr_generate_pucch3_4] block-wise spreading for format 4 (n_SF_PUCCH_s 2) (occ_Index=%d): (l,k)=(%d,%d)\ty_n(%d) = \t(d_re=%d, d_im=%d)\n", - occ_Index,l,k,l*(12*nrofPRB)+k,y_n_re[l*(12*nrofPRB)+k],y_n_im[l*(12*nrofPRB)+k]); - // printf("\t\t d_re[l*(12*nrofPRB/n_SF_PUCCH_s)+k%(12*nrofPRB/n_SF_PUCCH_s)] = %d\n",d_re[l*(12*nrofPRB/n_SF_PUCCH_s)+k%(12*nrofPRB/n_SF_PUCCH_s)]); - // printf("\t\t d_im[l*(12*nrofPRB/n_SF_PUCCH_s)+k%(12*nrofPRB/n_SF_PUCCH_s)] = %d\n",d_im[l*(12*nrofPRB/n_SF_PUCCH_s)+k%(12*nrofPRB/n_SF_PUCCH_s)]); - // printf("\t\t table_6_3_2_6_3_1_Wn_Re[%d][%d] = %d\n",occ_Index,k,table_6_3_2_6_3_1_Wn_Re[occ_Index][k]); - // printf("\t\t table_6_3_2_6_3_1_Wn_Im[%d][%d] = %d\n",occ_Index,k,table_6_3_2_6_3_1_Wn_Im[occ_Index][k]); + printf( + "\t [nr_generate_pucch3_4] block-wise spreading for format 4 (n_SF_PUCCH_s 2) (occ_Index=%d): (l,k)=(%d,%d)\ty_n(%d) " + " = \t(d_re=%d, d_im=%d)\n", + occ_Index, + l, + k, + l * (12 * nrofPRB) + k, + yPtr->r, + yPtr->i); #endif } if (n_SF_PUCCH_s == 4) { - y_n_re[l*(12*nrofPRB)+k] = (uint16_t)(((uint32_t)d_re[l*(12*nrofPRB/n_SF_PUCCH_s)+k%(12*nrofPRB/n_SF_PUCCH_s)] * table_6_3_2_6_3_2_Wn_Re[occ_Index][k]) - - ((uint32_t)d_im[l*(12*nrofPRB/n_SF_PUCCH_s)+k%(12*nrofPRB/n_SF_PUCCH_s)] * table_6_3_2_6_3_2_Wn_Im[occ_Index][k])); - y_n_im[l*(12*nrofPRB)+k] = (uint16_t)(((uint32_t)d_im[l*(12*nrofPRB/n_SF_PUCCH_s)+k%(12*nrofPRB/n_SF_PUCCH_s)] * table_6_3_2_6_3_2_Wn_Re[occ_Index][k]) - + ((uint32_t)d_re[l*(12*nrofPRB/n_SF_PUCCH_s)+k%(12*nrofPRB/n_SF_PUCCH_s)] * table_6_3_2_6_3_2_Wn_Im[occ_Index][k])); + c16_t table = {table_6_3_2_6_3_2_Wn_Re[occ_Index][k], table_6_3_2_6_3_2_Wn_Im[occ_Index][k]}; + *yPtr = c16mulShift(table, dVal, 15); #ifdef DEBUG_NR_PUCCH_TX - printf("\t [nr_generate_pucch3_4] block-wise spreading for format 4 (n_SF_PUCCH_s 4) (occ_Index=%d): (l,k)=(%d,%d)\ty_n(%d) = \t(d_re=%d, d_im=%d)\n", - occ_Index,l,k,l*(12*nrofPRB)+k,y_n_re[l*(12*nrofPRB)+k],y_n_im[l*(12*nrofPRB)+k]); + printf( + "\t [nr_generate_pucch3_4] block-wise spreading for format 4 (n_SF_PUCCH_s 4) (occ_Index=%d): (l,k)=(%d,%d)\ty_n(%d) " + " = \t(d_re=%d, d_im=%d)\n", + occ_Index, + l, + k, + l * 12 * nrofPRB + k, + yPtr->r, + yPtr->i); #endif } } @@ -1102,41 +1050,28 @@ void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, /* * Implementing Transform pre-coding subclause 6.3.2.6.4 */ - int16_t *z_re = malloc(sizeof(int16_t)*4*M_bit); // 4 is the maximum number n_SF_PUCCH_s - int16_t *z_im = malloc(sizeof(int16_t)*4*M_bit); + c16_t z[4 * M_bit]; // 4 is the maximum number n_SF_PUCCH_s #define M_PI 3.14159265358979323846 // pi - - //int16_t inv_sqrt_nrofPRBs = (int16_t)round(32767/sqrt(12*nrofPRB)); + const int64_t base = round(32767 / sqrt(12 * nrofPRB)); for (int l=0; l>15) - // + (((int32_t)y_n_im[l*(12*nrofPRB)+m] * (int16_t)round(32767 * sin(2*M_PI*m*k/(12*nrofPRB))))>>15)))>>15); - // z_im_tmp[m] = (int16_t)(((int32_t)round(32767/sqrt(12*nrofPRB))*(int16_t)((((int32_t)y_n_im[l*(12*nrofPRB)+m] * (int16_t)round(32767 * cos(2*M_PI*m*k/(12*nrofPRB))))>>15) - // - (((int32_t)y_n_re[l*(12*nrofPRB)+m] * (int16_t)round(32767 * sin(2*M_PI*m*k/(12*nrofPRB))))>>15)))>>15); - z_re[l*(12*nrofPRB)+k] = z_re[l*(12*nrofPRB)+k] - + (int16_t)(((int32_t)round(32767/sqrt(12*nrofPRB))*(int16_t)((((int32_t)y_n_re[l*(12*nrofPRB)+m] * (int16_t)round(32767 * cos(2*M_PI*m*k/(12*nrofPRB))))>>15) - + (((int32_t)y_n_im[l*(12*nrofPRB)+m] * (int16_t)round(32767 * sin(2*M_PI*m*k/(12*nrofPRB))))>>15)))>>15); - z_im[l*(12*nrofPRB)+k] = z_im[l*(12*nrofPRB)+k] - + (int16_t)(((int32_t)round(32767/sqrt(12*nrofPRB))*(int16_t)((((int32_t)y_n_im[l*(12*nrofPRB)+m] * (int16_t)round(32767 * cos(2*M_PI*m*k/(12*nrofPRB))))>>15) - - (((int32_t)y_n_re[l*(12*nrofPRB)+m] * (int16_t)round(32767 * sin(2*M_PI*m*k/(12*nrofPRB))))>>15)))>>15); -#ifdef DEBUG_NR_PUCCH_TX - // printf("\t\t z_re_tmp[%d] = %d\n",m,z_re_tmp[m]); - // printf("\t\t z_im_tmp[%d] = %d\n",m,z_im_tmp[m]); - // printf("\t [nr_generate_pucch3_4] transform precoding for formats 3 and 4: (l,k,m)=(%d,%d,%d)\tz(%d) = \t(%d, %d)\n", - // l,k,m,l*(12*nrofPRB)+k,z_re[l*(12*nrofPRB)+k],z_im[l*(12*nrofPRB)+k]); -#endif + c16_t *yPtr = y_n + l * 12 * nrofPRB; + c16_t *zPtr = z + l * 12 * nrofPRB + k; + *zPtr = (c16_t){0}; + for (int m = l * 12 * nrofPRB; m < (l + 1) * 12 * nrofPRB; m++) { + const c16_t angle = {lround(32767 * cos(2 * M_PI * m * k / (12 * nrofPRB))), + lround(32767 * sin(2 * M_PI * m * k / (12 * nrofPRB)))}; + c16_t tmp = c16mulShift(yPtr[m], angle, 15); + csum(*zPtr, *zPtr, c16mulRealShift(tmp, base, 15)); } #ifdef DEBUG_NR_PUCCH_TX printf("\t [nr_generate_pucch3_4] transform precoding for formats 3 and 4: (l,k)=(%d,%d)\tz(%d) = \t(%d, %d)\n", - l,k,l*(12*nrofPRB)+k,z_re[l*(12*nrofPRB)+k],z_im[l*(12*nrofPRB)+k]); + l, + k, + l * (12 * nrofPRB) + k, + zPtr->r, + zPtr->i); #endif } } @@ -1157,10 +1092,11 @@ void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, // lprime is the index of the OFDM symbol in the slot that corresponds to the first OFDM symbol of the PUCCH transmission in the slot given by [5, TS 38.213] //uint8_t lprime = startingSymbolIndex; // m0 is the cyclic shift index calculated depending on the Orthogonal sequence index n, according to table 6.4.1.3.3.1-1 from TS 38.211 subclause 6.4.1.3.3.1 - uint8_t m0; + uint8_t m0 = 0; uint8_t mcs=0; - if (pucch_pdu->format_type == 3) m0 = 0; + if (pucch_pdu->format_type == 3) + m0 = 0; if (pucch_pdu->format_type == 4) { if (n_SF_PUCCH_s == 2) { @@ -1173,17 +1109,9 @@ void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, } double alpha; - uint8_t N_ZC = 12*nrofPRB; - int16_t *r_u_v_base_re = malloc(sizeof(int16_t)*12*nrofPRB); - int16_t *r_u_v_base_im = malloc(sizeof(int16_t)*12*nrofPRB); - //int16_t *r_u_v_alpha_delta_re = malloc(sizeof(int16_t)*12*nrofPRB); - //int16_t *r_u_v_alpha_delta_im = malloc(sizeof(int16_t)*12*nrofPRB); - // Next we proceed to mapping to physical resources according to TS 38.211, subclause 6.3.2.6.5 dor PUCCH formats 3 and 4 and subclause 6.4.1.3.3.2 for DM-RS - //int32_t *txptr; - uint32_t re_offset=0; - //uint32_t x1, x2, s=0; - // intraSlotFrequencyHopping - // uint8_t intraSlotFrequencyHopping = 0; + int N_ZC = 12 * nrofPRB; + c16_t r_u_v_base[N_ZC]; + uint32_t re_offset = 0; uint8_t table_6_4_1_3_3_2_1_dmrs_positions[11][14] = { {(intraSlotFrequencyHopping==0)?0:1,(intraSlotFrequencyHopping==0)?1:0,(intraSlotFrequencyHopping==0)?0:1,0,0,0,0,0,0,0,0,0,0,0}, // PUCCH length = 4 {1,0,0,1,0,0,0,0,0,0,0,0,0,0}, // PUCCH length = 5 @@ -1197,10 +1125,11 @@ void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, {0,(add_dmrs==0?0:1),(add_dmrs==0?1:0),0,(add_dmrs==0?0:1),0,0,(add_dmrs==0?0:1),0,(add_dmrs==0?1:0),0,(add_dmrs==0?0:1),0,0}, // PUCCH length = 13 {0,(add_dmrs==0?0:1),0,(add_dmrs==0?1:0),0,(add_dmrs==0?0:1),0,0,(add_dmrs==0?0:1),0,(add_dmrs==0?1:0),0,(add_dmrs==0?0:1),0} // PUCCH length = 14 }; - uint16_t k=0; + int k = 0; for (int l=0; l= (int)floor(nrofSymbols/2))) n_hop = 1; // n_hop = 1 for second hop + if ((intraSlotFrequencyHopping == 1) && (l >= (int)floor(nrofSymbols / 2))) + n_hop = 1; // n_hop = 1 for second hop pucch_GroupHopping_t pucch_GroupHopping = pucch_pdu->group_hop_flag + (pucch_pdu->sequence_hop_flag<<1); nr_group_sequence_hopping(pucch_GroupHopping,pucch_pdu->hopping_id,n_hop,nr_slot_tx,&u,&v); // calculating u and v value @@ -1217,33 +1146,43 @@ void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, q = ((uint8_t)floor(2*q_base)%2 == 0 ? q+v : q-v); for (int n=0; n<(12*nrofPRB); n++) { - r_u_v_base_re[n] = (int16_t)(((int32_t)amp*(int16_t)(32767*cos(M_PI*q*(n%N_ZC)*((n%N_ZC)+1)/N_ZC)))>>15); - r_u_v_base_im[n] = -(int16_t)(((int32_t)amp*(int16_t)(32767*sin(M_PI*q*(n%N_ZC)*((n%N_ZC)+1)/N_ZC)))>>15); + const double tmp = M_PI * q * (n % N_ZC) * ((n % N_ZC) + 1) / N_ZC; + r_u_v_base[n].r = lround(amp * 32767 * cos(tmp)) >> 15; + r_u_v_base[n].i = -lround(amp * 32767 * sin(tmp)) >> 15; #ifdef DEBUG_NR_PUCCH_TX printf("\t [nr_generate_pucch3_4] generation DM-RS base sequence when nrofPRB=%d >= 3: r_u_v_base[n=%d]=(%d,%d)\n", - nrofPRB,n,r_u_v_base_re[n],r_u_v_base_im[n]); + nrofPRB, + n, + r_u_v_base[n].r, + r_u_v_base[n].i); #endif } } if (nrofPRB == 2) { // TS 38.211 subclause 5.2.2.2 (Base sequences of length less than 36 using table 5.2.2.2-4) applies - for (int n=0; n<(12*nrofPRB); n++) { - r_u_v_base_re[n] = (int16_t)(((int32_t)amp*table_5_2_2_2_4_Re[u][n])>>15); - r_u_v_base_im[n] = (int16_t)(((int32_t)amp*table_5_2_2_2_4_Im[u][n])>>15); + for (int n = 0; n < 12 * nrofPRB; n++) { + c16_t table = {table_5_2_2_2_4_Re[u][n], table_5_2_2_2_4_Im[u][n]}; + r_u_v_base[n] = c16mulRealShift(table, amp, 15); #ifdef DEBUG_NR_PUCCH_TX printf("\t [nr_generate_pucch3_4] generation DM-RS base sequence when nrofPRB=%d == 2: r_u_v_base[n=%d]=(%d,%d)\n", - nrofPRB,n,r_u_v_base_re[n],r_u_v_base_im[n]); + nrofPRB, + n, + r_u_v_base[n].r, + r_u_v_base[n].i); #endif } } if (nrofPRB == 1) { // TS 38.211 subclause 5.2.2.2 (Base sequences of length less than 36 using table 5.2.2.2-2) applies - for (int n=0; n<(12*nrofPRB); n++) { - r_u_v_base_re[n] = (int16_t)(((int32_t)amp*table_5_2_2_2_2_Re[u][n])>>15); - r_u_v_base_im[n] = (int16_t)(((int32_t)amp*table_5_2_2_2_2_Im[u][n])>>15); + for (int n = 0; n < 12 * nrofPRB; n++) { + c16_t table = {table_5_2_2_2_2_Re[u][n], table_5_2_2_2_2_Im[u][n]}; + r_u_v_base[n] = c16mulRealShift(table, amp, 15); #ifdef DEBUG_NR_PUCCH_TX printf("\t [nr_generate_pucch3_4] generation DM-RS base sequence when nrofPRB=%d == 1: r_u_v_base[n=%d]=(%d,%d)\n", - nrofPRB,n,r_u_v_base_re[n],r_u_v_base_im[n]); + nrofPRB, + n, + r_u_v_base[n].r, + r_u_v_base[n].i); #endif } } @@ -1253,76 +1192,102 @@ void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, alpha = nr_cyclic_shift_hopping(pucch_pdu->hopping_id,m0,mcs,l,startingSymbolIndex,nr_slot_tx); for (int rb=0; rbN_RB_DL & 1; + const int halfRBs = frame_parms->N_RB_DL / 2; + const int baseRB = rb + startingPRB; if ((intraSlotFrequencyHopping == 1) && (lsecond_hop_prb; } - + re_offset = ((l + startingSymbolIndex) * frame_parms->ofdm_symbol_size); //startingPRB = startingPRB + rb; - if (((rb+startingPRB) < (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 0)) { // if number RBs in bandwidth is even and current PRB is lower band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*(rb+startingPRB)) + frame_parms->first_carrier_offset; + if (nb_rb_is_even) { + if (baseRB < halfRBs) { // if number RBs in bandwidth is even and current PRB is lower band + re_offset += 12 * baseRB + frame_parms->first_carrier_offset; #ifdef DEBUG_NR_PUCCH_TX printf("1 "); #endif - } + } - if (((rb+startingPRB) >= (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 0)) { // if number RBs in bandwidth is even and current PRB is upper band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*((rb+startingPRB)-(frame_parms->N_RB_DL>>1))); + else { // if number RBs in bandwidth is even and current PRB is upper band + re_offset += 12 * (baseRB - halfRBs); #ifdef DEBUG_NR_PUCCH_TX printf("2 "); #endif - } - - if (((rb+startingPRB) < (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd and current PRB is lower band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*(rb+startingPRB)) + frame_parms->first_carrier_offset; + } + } else { + if (baseRB < halfRBs) { // if number RBs in bandwidth is odd and current PRB is lower band + re_offset += 12 * baseRB + frame_parms->first_carrier_offset; #ifdef DEBUG_NR_PUCCH_TX printf("3 "); #endif - } - - if (((rb+startingPRB) > (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd and current PRB is upper band - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*((rb+startingPRB)-(frame_parms->N_RB_DL>>1))) + 6; + } else if (baseRB > halfRBs) { // if number RBs in bandwidth is odd and current PRB is upper band + re_offset += 12 * (baseRB - halfRBs) + 6; #ifdef DEBUG_NR_PUCCH_TX printf("4 "); #endif - } - - if (((rb+startingPRB) == (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { // if number RBs in bandwidth is odd and current PRB contains DC - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size) + (12*(rb+startingPRB)) + frame_parms->first_carrier_offset; + } else { // if number RBs in bandwidth is odd and current PRB contains DC + re_offset += 12 * baseRB + frame_parms->first_carrier_offset; #ifdef DEBUG_NR_PUCCH_TX printf("5 "); #endif + } } #ifdef DEBUG_NR_PUCCH_TX - printf("re_offset=%u,(rb+startingPRB)=%d\n",re_offset,(rb+startingPRB)); + printf("re_offset=%u,baseRB=%d\n", re_offset, baseRB); #endif //txptr = &txdataF[0][re_offset]; for (int n=0; n<12; n++) { - if ((n==6) && ((rb+startingPRB) == (frame_parms->N_RB_DL>>1)) && ((frame_parms->N_RB_DL & 1) == 1)) { - // if number RBs in bandwidth is odd and current PRB contains DC, we need to recalculate the offset when n=6 (for second half PRB) - re_offset = ((l+startingSymbolIndex)*frame_parms->ofdm_symbol_size); + if ((n == 6) && baseRB == halfRBs && !nb_rb_is_even) { + // if number RBs in bandwidth is odd and current PRB contains DC, we need to recalculate the offset when n=6 (for second + // half PRB) + re_offset = ((l + startingSymbolIndex) * frame_parms->ofdm_symbol_size); } if (table_6_4_1_3_3_2_1_dmrs_positions[nrofSymbols-4][l] == 0) { // mapping PUCCH according to TS38.211 subclause 6.3.2.5.3 - ((int16_t *)&txdataF[0][re_offset])[0] = z_re[n+k]; - ((int16_t *)&txdataF[0][re_offset])[1] = z_im[n+k]; + txdataF[0][re_offset] = z[n + k]; #ifdef DEBUG_NR_PUCCH_TX - printf("\t [nr_generate_pucch3_4] (l=%d,rb=%d,n=%d,k=%d) mapping PUCCH to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \tz_pucch[%d]=txptr(%u)=(z(l=%d,n=%d)=(%d,%d))\n", - l,rb,n,k,amp,frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,n+k,re_offset, - l,n,((int16_t *)&txdataF[0][re_offset])[0],((int16_t *)&txdataF[0][re_offset])[1]); + printf( + "\t [nr_generate_pucch3_4] (l=%d,rb=%d,n=%d,k=%d) mapping PUCCH to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d " + "\tfirst_carrier_offset=%d \tz_pucch[%d]=txptr(%u)=(z(l=%d,n=%d)=(%d,%d))\n", + l, + rb, + n, + k, + amp, + frame_parms->ofdm_symbol_size, + frame_parms->N_RB_DL, + frame_parms->first_carrier_offset, + n + k, + re_offset, + l, + n, + txdataF[0][re_offset].r, + txdataF[0][re_offset].i); #endif } - if (table_6_4_1_3_3_2_1_dmrs_positions[nrofSymbols-4][l] == 1) { // mapping DM-RS signal according to TS38.211 subclause 6.4.1.3.2 - ((int16_t *)&txdataF[0][re_offset])[0] = (int16_t)((((int32_t)(32767*cos(alpha*((n+j)%N_ZC)))*r_u_v_base_re[n+j])>>15) - - (((int32_t)(32767*sin(alpha*((n+j)%N_ZC)))*r_u_v_base_im[n+j])>>15)); - ((int16_t *)&txdataF[0][re_offset])[1] = (int16_t)((((int32_t)(32767*cos(alpha*((n+j)%N_ZC)))*r_u_v_base_im[n+j])>>15) - + (((int32_t)(32767*sin(alpha*((n+j)%N_ZC)))*r_u_v_base_re[n+j])>>15)); + const c16_t angle = {lround(32767 * cos(alpha * ((n + j) % N_ZC))), lround(32767 * sin(alpha * ((n + j) % N_ZC)))}; + txdataF[0][re_offset] = c16mulShift(angle, r_u_v_base[n + j], 15); #ifdef DEBUG_NR_PUCCH_TX - printf("\t [nr_generate_pucch3_4] (l=%d,rb=%d,n=%d,j=%d) mapping DM-RS to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d \tfirst_carrier_offset=%d \tz_dm-rs[%d]=txptr(%u)=(r_u_v(l=%d,n=%d)=(%d,%d))\n", - l,rb,n,j,amp,frame_parms->ofdm_symbol_size,frame_parms->N_RB_DL,frame_parms->first_carrier_offset,n+j,re_offset, - l,n,((int16_t *)&txdataF[0][re_offset])[0],((int16_t *)&txdataF[0][re_offset])[1]); + printf( + "\t [nr_generate_pucch3_4] (l=%d,rb=%d,n=%d,j=%d) mapping DM-RS to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d " + "\tfirst_carrier_offset=%d \tz_dm-rs[%d]=txptr(%u)=(r_u_v(l=%d,n=%d)=(%d,%d))\n", + l, + rb, + n, + j, + amp, + frame_parms->ofdm_symbol_size, + frame_parms->N_RB_DL, + frame_parms->first_carrier_offset, + n + j, + re_offset, + l, + n, + txdataF[0][re_offset].r, + txdataF[0][re_offset].i); #endif } @@ -1334,7 +1299,4 @@ void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, if (table_6_4_1_3_3_2_1_dmrs_positions[nrofSymbols-4][l] == 1) j+=12; } } - free(z_re); - free(z_im); - free(btilde); } diff --git a/openair1/PHY/TOOLS/tools_defs.h b/openair1/PHY/TOOLS/tools_defs.h index e98b20b277..cd99eb497e 100644 --- a/openair1/PHY/TOOLS/tools_defs.h +++ b/openair1/PHY/TOOLS/tools_defs.h @@ -215,7 +215,8 @@ extern "C" { { return (c16_t){.r = (int16_t)((a.r * b) >> Shift), .i = (int16_t)((a.i * b) >> Shift)}; } - __attribute__((always_inline)) inline c16_t c16divShift(const c16_t a, const c16_t b, const int Shift) { + __attribute__((always_inline)) inline c16_t c16MulConjShift(const c16_t a, const c16_t b, const int Shift) + { return (c16_t) { .r = (int16_t)((a.r * b.r + a.i * b.i) >> Shift), .i = (int16_t)((a.r * b.i - a.i * b.r) >> Shift) diff --git a/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c b/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c index 3f99a22b71..fddb484727 100644 --- a/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c +++ b/openair1/SCHED_NR_UE/pucch_uci_ue_nr.c @@ -83,64 +83,7 @@ binary_search_float_nr( return first; } -/* -void nr_generate_pucch0(int32_t **txdataF, - NR_DL_FRAME_PARMS *frame_parms, - PUCCH_CONFIG_DEDICATED *pucch_config_dedicated, - int16_t amp, - int nr_slot_tx, - uint8_t mcs, - uint8_t nrofSymbols, - uint8_t startingSymbolIndex, - uint16_t startingPRB); -void nr_generate_pucch1(int32_t **txdataF, - NR_DL_FRAME_PARMS *frame_parms, - PUCCH_CONFIG_DEDICATED *pucch_config_dedicated, - uint64_t payload, - int16_t amp, - int nr_slot_tx, - uint8_t nrofSymbols, - uint8_t startingSymbolIndex, - uint16_t startingPRB, - uint16_t startingPRB_intraSlotHopping, - uint8_t timeDomainOCC, - uint8_t nr_bit); - -void nr_generate_pucch2(int32_t **txdataF, - NR_DL_FRAME_PARMS *frame_parms, - PUCCH_CONFIG_DEDICATED *pucch_config_dedicated, - uint64_t payload, - int16_t amp, - int nr_slot_tx, - uint8_t nrofSymbols, - uint8_t startingSymbolIndex, - uint8_t nrofPRB, - uint16_t startingPRB, - uint8_t nr_bit); - -void nr_generate_pucch3_4(int32_t **txdataF, - NR_DL_FRAME_PARMS *frame_parms, - pucch_format_nr_t fmt, - PUCCH_CONFIG_DEDICATED *pucch_config_dedicated, - uint64_t payload, - int16_t amp, - int nr_slot_tx, - uint8_t nrofSymbols, - uint8_t startingSymbolIndex, - uint8_t nrofPRB, - uint16_t startingPRB, - uint8_t nr_bit, - uint8_t occ_length_format4, - uint8_t occ_index_format4); -*/ -/**************** variables **************************************/ - - -/**************** functions **************************************/ - -//extern uint8_t is_cqi_TXOp(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t eNB_id); -//extern uint8_t is_ri_TXOp(PHY_VARS_NR_UE *ue,UE_nr_rxtx_proc_t *proc,uint8_t eNB_id); /******************************************************************* * * NAME : pucch_procedures_ue_nr diff --git a/openair2/COMMON/as_message.h b/openair2/COMMON/as_message.h index 4973939976..180b580916 100644 --- a/openair2/COMMON/as_message.h +++ b/openair2/COMMON/as_message.h @@ -401,6 +401,10 @@ typedef struct nas_deregistration_req_s { release_cause_t cause; } nas_deregistration_req_t; +typedef struct nas_detach_req_s { + bool wait_release; +} nas_detach_req_t; + /* * -------------------------------------------------------------------------- * NAS information transfer diff --git a/openair2/COMMON/rrc_messages_def.h b/openair2/COMMON/rrc_messages_def.h index f43d7a8dc5..355b8b3e90 100644 --- a/openair2/COMMON/rrc_messages_def.h +++ b/openair2/COMMON/rrc_messages_def.h @@ -61,6 +61,7 @@ MESSAGE_DEF(NAS_KENB_REFRESH_REQ, MESSAGE_PRIORITY_MED, NasKenbRefre MESSAGE_DEF(NAS_CELL_SELECTION_REQ, MESSAGE_PRIORITY_MED, NasCellSelectionReq, nas_cell_selection_req) MESSAGE_DEF(NAS_CONN_ESTABLI_REQ, MESSAGE_PRIORITY_MED, NasConnEstabliReq, nas_conn_establi_req) MESSAGE_DEF(NAS_UPLINK_DATA_REQ, MESSAGE_PRIORITY_MED, NasUlDataReq, nas_ul_data_req) +MESSAGE_DEF(NAS_DETACH_REQ, MESSAGE_PRIORITY_MED, NasDetachReq, nas_detach_req) MESSAGE_DEF(NAS_DEREGISTRATION_REQ, MESSAGE_PRIORITY_MED, NasDeregistrationReq, nas_deregistration_req) MESSAGE_DEF(NAS_RAB_ESTABLI_RSP, MESSAGE_PRIORITY_MED, NasRabEstRsp, nas_rab_est_rsp) diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h index 8fc3a8514a..ccc2d9f030 100644 --- a/openair2/COMMON/rrc_messages_types.h +++ b/openair2/COMMON/rrc_messages_types.h @@ -74,6 +74,7 @@ #define NAS_CELL_SELECTION_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_cell_selection_req #define NAS_CONN_ESTABLI_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_conn_establi_req #define NAS_UPLINK_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_ul_data_req +#define NAS_DETACH_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_detach_req #define NAS_DEREGISTRATION_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_deregistration_req #define NAS_RAB_ESTABLI_RSP(mSGpTR) (mSGpTR)->ittiMsg.nas_rab_est_rsp @@ -429,6 +430,7 @@ typedef cell_info_req_t NasCellSelectionReq; typedef nas_establish_req_t NasConnEstabliReq; typedef ul_info_transfer_req_t NasUlDataReq; typedef nas_deregistration_req_t NasDeregistrationReq; +typedef nas_detach_req_t NasDetachReq; typedef rab_establish_rsp_t NasRabEstRsp; diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index 018cfcb406..1080ee7faa 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -4431,20 +4431,18 @@ void get_type0_PDCCH_CSS_config_parameters(NR_Type0_PDCCH_CSS_config_t *type0_PD type0_PDCCH_CSS_config->cset_start_rb = ssb_offset_point_a - type0_PDCCH_CSS_config->rb_offset; } -void fill_coresetZero(NR_ControlResourceSet_t *coreset0, NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config) { - - int32_t duration; - +void fill_coresetZero(NR_ControlResourceSet_t *coreset0, NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config) +{ if (coreset0 == NULL) coreset0 = calloc(1,sizeof(*coreset0)); - coreset0->controlResourceSetId = 0; - AssertFatal(type0_PDCCH_CSS_config!=NULL,"No type0 CSS configuration\n"); - duration = type0_PDCCH_CSS_config->num_symbols; + coreset0->controlResourceSetId = 0; + int duration = type0_PDCCH_CSS_config->num_symbols; - if(coreset0->frequencyDomainResources.buf == NULL) coreset0->frequencyDomainResources.buf = calloc(1,6); + if(coreset0->frequencyDomainResources.buf == NULL) + coreset0->frequencyDomainResources.buf = calloc(1,6); switch(type0_PDCCH_CSS_config->num_rbs){ case 24: @@ -4470,8 +4468,9 @@ void fill_coresetZero(NR_ControlResourceSet_t *coreset0, NR_Type0_PDCCH_CSS_conf coreset0->frequencyDomainResources.bits_unused = 3; coreset0->duration = duration; - coreset0->cce_REG_MappingType.present=NR_ControlResourceSet__cce_REG_MappingType_PR_interleaved; - coreset0->cce_REG_MappingType.choice.interleaved=calloc(1,sizeof(*coreset0->cce_REG_MappingType.choice.interleaved)); + coreset0->cce_REG_MappingType.present = NR_ControlResourceSet__cce_REG_MappingType_PR_interleaved; + if (!coreset0->cce_REG_MappingType.choice.interleaved) + coreset0->cce_REG_MappingType.choice.interleaved = calloc(1,sizeof(*coreset0->cce_REG_MappingType.choice.interleaved)); coreset0->cce_REG_MappingType.choice.interleaved->reg_BundleSize = NR_ControlResourceSet__cce_REG_MappingType__interleaved__reg_BundleSize_n6; coreset0->cce_REG_MappingType.choice.interleaved->interleaverSize = NR_ControlResourceSet__cce_REG_MappingType__interleaved__interleaverSize_n2; coreset0->cce_REG_MappingType.choice.interleaved->shiftIndex = NULL; // -> use cell_id @@ -4481,23 +4480,28 @@ void fill_coresetZero(NR_ControlResourceSet_t *coreset0, NR_Type0_PDCCH_CSS_conf coreset0->tci_StatesPDCCH_ToReleaseList = NULL; coreset0->tci_PresentInDCI = NULL; coreset0->pdcch_DMRS_ScramblingID = NULL; - } void fill_searchSpaceZero(NR_SearchSpace_t *ss0, int slots_per_frame, NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config) { - - if(ss0 == NULL) ss0=calloc(1,sizeof(*ss0)); - if(ss0->controlResourceSetId == NULL) ss0->controlResourceSetId=calloc(1,sizeof(*ss0->controlResourceSetId)); - if(ss0->monitoringSymbolsWithinSlot == NULL) ss0->monitoringSymbolsWithinSlot = calloc(1,sizeof(*ss0->monitoringSymbolsWithinSlot)); - if(ss0->monitoringSymbolsWithinSlot->buf == NULL) ss0->monitoringSymbolsWithinSlot->buf = calloc(1,2); - if(ss0->nrofCandidates == NULL) ss0->nrofCandidates = calloc(1,sizeof(*ss0->nrofCandidates)); - if(ss0->searchSpaceType == NULL) ss0->searchSpaceType = calloc(1,sizeof(*ss0->searchSpaceType)); - if(ss0->searchSpaceType->choice.common == NULL) ss0->searchSpaceType->choice.common=calloc(1,sizeof(*ss0->searchSpaceType->choice.common)); + if(ss0 == NULL) + ss0 = calloc(1, sizeof(*ss0)); + if(ss0->controlResourceSetId == NULL) + ss0->controlResourceSetId = calloc(1, sizeof(*ss0->controlResourceSetId)); + if(ss0->monitoringSymbolsWithinSlot == NULL) + ss0->monitoringSymbolsWithinSlot = calloc(1, sizeof(*ss0->monitoringSymbolsWithinSlot)); + if(ss0->monitoringSymbolsWithinSlot->buf == NULL) + ss0->monitoringSymbolsWithinSlot->buf = calloc(1, 2); + if(ss0->nrofCandidates == NULL) + ss0->nrofCandidates = calloc(1, sizeof(*ss0->nrofCandidates)); + if(ss0->searchSpaceType == NULL) + ss0->searchSpaceType = calloc(1, sizeof(*ss0->searchSpaceType)); + if(ss0->searchSpaceType->choice.common == NULL) + ss0->searchSpaceType->choice.common = calloc(1, sizeof(*ss0->searchSpaceType->choice.common)); if(ss0->searchSpaceType->choice.common->dci_Format0_0_AndFormat1_0 == NULL) - ss0->searchSpaceType->choice.common->dci_Format0_0_AndFormat1_0 = calloc(1,sizeof(*ss0->searchSpaceType->choice.common->dci_Format0_0_AndFormat1_0)); + ss0->searchSpaceType->choice.common->dci_Format0_0_AndFormat1_0 = calloc(1, sizeof(*ss0->searchSpaceType->choice.common->dci_Format0_0_AndFormat1_0)); AssertFatal(type0_PDCCH_CSS_config!=NULL,"No type0 CSS configuration\n"); @@ -4508,13 +4512,15 @@ void fill_searchSpaceZero(NR_SearchSpace_t *ss0, ss0->searchSpaceId = 0; *ss0->controlResourceSetId = 0; - ss0->monitoringSlotPeriodicityAndOffset = calloc(1,sizeof(*ss0->monitoringSlotPeriodicityAndOffset)); + if(ss0->monitoringSlotPeriodicityAndOffset == NULL) + ss0->monitoringSlotPeriodicityAndOffset = calloc(1, sizeof(*ss0->monitoringSlotPeriodicityAndOffset)); set_monitoring_periodicity_offset(ss0,periodicity,offset); const uint32_t duration = type0_PDCCH_CSS_config->search_space_duration; if (duration==1) ss0->duration = NULL; else{ - ss0->duration = calloc(1,sizeof(*ss0->duration)); + if (!ss0->duration) + ss0->duration = calloc(1, sizeof(*ss0->duration)); *ss0->duration = duration; } diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 146e7a6f4f..7e7da9c4f8 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -795,6 +795,22 @@ void ue_init_config_request(NR_UE_MAC_INST_t *mac, int scs) pthread_mutex_init(&(mac->ul_config_request[i].mutex_ul_config), NULL); } +static void update_mib_conf(NR_MIB_t *target, NR_MIB_t *source) +{ + target->systemFrameNumber.size = source->systemFrameNumber.size; + target->systemFrameNumber.bits_unused = source->systemFrameNumber.bits_unused; + if (!target->systemFrameNumber.buf) + target->systemFrameNumber.buf = calloc(target->systemFrameNumber.size, sizeof(*target->systemFrameNumber.buf)); + for (int i = 0; i < target->systemFrameNumber.size; i++) + target->systemFrameNumber.buf[i] = source->systemFrameNumber.buf[i]; + target->subCarrierSpacingCommon = source->subCarrierSpacingCommon; + target->ssb_SubcarrierOffset = source->ssb_SubcarrierOffset; + target->dmrs_TypeA_Position = source->dmrs_TypeA_Position; + target->pdcch_ConfigSIB1 = source->pdcch_ConfigSIB1; + target->cellBarred = source->cellBarred; + target->intraFreqReselection = source->intraFreqReselection; +} + void nr_rrc_mac_config_req_mib(module_id_t module_id, int cc_idP, NR_MIB_t *mib, @@ -802,16 +818,16 @@ void nr_rrc_mac_config_req_mib(module_id_t module_id, { NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); AssertFatal(mib, "MIB should not be NULL\n"); - // initialize dl and ul config_request upon first reception of MIB - mac->mib = mib; // update by every reception + if (!mac->mib) + mac->mib = calloc(1, sizeof(*mac->mib)); + update_mib_conf(mac->mib, mib); mac->phy_config.Mod_id = module_id; mac->phy_config.CC_id = cc_idP; if (sched_sib == 1) mac->get_sib1 = true; else if (sched_sib == 2) mac->get_otherSI = true; - nr_ue_decode_mib(module_id, - cc_idP); + nr_ue_decode_mib(module_id, cc_idP); } static void setup_puschpowercontrol(NR_PUSCH_PowerControl_t *source, NR_PUSCH_PowerControl_t *target) @@ -1365,11 +1381,12 @@ void nr_rrc_mac_config_req_reset(module_id_t module_id, // Sending to PHY a request to resync // with no target cell ID - mac->synch_request.Mod_id = module_id; - mac->synch_request.CC_id = 0; - mac->synch_request.synch_req.target_Nid_cell = -1; - mac->if_module->synch_request(&mac->synch_request); - + if (reset_cause != DETACH) { + mac->synch_request.Mod_id = module_id; + mac->synch_request.CC_id = 0; + mac->synch_request.synch_req.target_Nid_cell = -1; + mac->if_module->synch_request(&mac->synch_request); + } } void nr_rrc_mac_config_req_sib1(module_id_t module_id, diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index d92e0c4fa7..4c010304b7 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -167,6 +167,8 @@ typedef enum { typedef enum { GO_TO_IDLE, + DETACH, + T300_EXPIRY, RE_ESTABLISHMENT } NR_UE_MAC_reset_cause_t; diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index 0131551ed2..6ae2df12eb 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -198,6 +198,7 @@ void release_mac_configuration(NR_UE_MAC_INST_t *mac) free(sc->nrofHARQ_ProcessesForPDSCH); free(sc->rateMatching_PUSCH); free(sc->xOverhead_PUSCH); + free(sc->maxMIMO_Layers_PDSCH); free(sc->maxMIMO_Layers_PUSCH); memset(&mac->sc_info, 0, sizeof(mac->sc_info)); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c index 075afc2bd9..1bd991f7c5 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c @@ -263,7 +263,7 @@ void config_dci_pdu(NR_UE_MAC_INST_t *mac, case NR_RNTI_SP_CSI: break; case NR_RNTI_SI: - sps=14; + sps = 14; // for SPS=14 8 MSBs in positions 13 down to 6 monitoringSymbolsWithinSlot = (ss->monitoringSymbolsWithinSlot->buf[0]<<(sps-8)) | (ss->monitoringSymbolsWithinSlot->buf[1]>>(16-sps)); rel15->rnti = SI_RNTI; // SI-RNTI - 3GPP TS 38.321 Table 7.1-1: RNTI values diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 91cc805d22..9118fce36a 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2352,8 +2352,7 @@ bool get_downlink_ack(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCCH_sche bool trigger_periodic_scheduling_request(NR_UE_MAC_INST_t *mac, PUCCH_sched_t *pucch, frame_t frame, int slot) { NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; - NR_PUCCH_Config_t *pucch_Config = current_UL_BWP->pucch_Config; - const int n_slots_frame = nr_slots_per_frame[current_UL_BWP->scs]; + NR_PUCCH_Config_t *pucch_Config = current_UL_BWP ? current_UL_BWP->pucch_Config : NULL; if(!pucch_Config || !pucch_Config->schedulingRequestResourceToAddModList || @@ -2366,6 +2365,7 @@ bool trigger_periodic_scheduling_request(NR_UE_MAC_INST_t *mac, PUCCH_sched_t *p int SR_period; int SR_offset; find_period_offset_SR(SchedulingRequestResourceConfig,&SR_period,&SR_offset); + const int n_slots_frame = nr_slots_per_frame[current_UL_BWP->scs]; int sfn_sf = frame * n_slots_frame + slot; if ((sfn_sf - SR_offset) % SR_period == 0) { @@ -2454,8 +2454,7 @@ int compute_csi_priority(NR_UE_MAC_INST_t *mac, NR_CSI_ReportConfig_t *csirep) int nr_get_csi_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCCH_sched_t *pucch) { NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; - NR_BWP_Id_t bwp_id = current_UL_BWP->bwp_id; - NR_PUCCH_Config_t *pucch_Config = current_UL_BWP->pucch_Config; + NR_PUCCH_Config_t *pucch_Config = current_UL_BWP ? current_UL_BWP->pucch_Config : NULL; int num_csi = 0; if (mac->sc_info.csi_MeasConfig) { @@ -2476,7 +2475,7 @@ int nr_get_csi_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCC for (int i = 0; i < csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.count; i++) { const NR_PUCCH_CSI_Resource_t *pucchcsires = csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.array[i]; - if (pucchcsires->uplinkBandwidthPartId == bwp_id) { + if (pucchcsires->uplinkBandwidthPartId == current_UL_BWP->bwp_id) { csi_res_id = pucchcsires->pucch_Resource; break; } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 8107f97abc..75e959f6cc 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -885,7 +885,7 @@ bool nr_ue_periodic_srs_scheduling(module_id_t mod_id, frame_t frame, slot_t slo NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id); NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; - NR_SRS_Config_t *srs_config = current_UL_BWP->srs_Config; + NR_SRS_Config_t *srs_config = current_UL_BWP ? current_UL_BWP->srs_Config : NULL; if (!srs_config) { return false; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index e1d63bc6d8..425782cddc 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -693,6 +693,21 @@ void nr_initiate_ra_proc(module_id_t module_idP, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 0); } +static void start_ra_contention_resolution_timer(NR_RA_t *ra, const long ra_ContentionResolutionTimer, const int K2, const int scs) +{ + // 3GPP TS 38.331 Section 6.3.2 Radio resource control information elements + // ra-ContentionResolutionTimer ENUMERATED {sf8, sf16, sf24, sf32, sf40, sf48, sf56, sf64} + // The initial value for the contention resolution timer. + // Value sf8 corresponds to 8 subframes, value sf16 corresponds to 16 subframes, and so on. + // We add K2 because we start the timer in the DL slot that schedules Msg3/Msg3 retransmission + ra->contention_resolution_timer = ((((int)ra_ContentionResolutionTimer + 1) * 8) << scs) + K2; + LOG_D(NR_MAC, + "Starting RA Contention Resolution timer with %d ms + %d K2 (%d slots) duration\n", + ((int)ra_ContentionResolutionTimer + 1) * 8, + K2, + ra->contention_resolution_timer); +} + static void nr_generate_Msg3_retransmission(module_id_t module_idP, int CC_id, frame_t frame, @@ -796,7 +811,7 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, ul_dci_request_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); pdcch_pdu_rel15 = &ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15; ul_dci_req->numPdus += 1; - nr_configure_pdcch(pdcch_pdu_rel15, coreset, false, &ra->sched_pdcch); + nr_configure_pdcch(pdcch_pdu_rel15, coreset, &ra->sched_pdcch); nr_mac->pdcch_pdu_idx[CC_id][coresetid] = pdcch_pdu_rel15; } @@ -861,6 +876,14 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, vrb_map_UL[rbStart + BWPStart + rb] |= SL_to_bitmap(StartSymbolIndex, NrOfSymbols); } + // Restart RA contention resolution timer in Msg3 retransmission slot (current slot + K2) + // 3GPP TS 38.321 Section 5.1.5 Contention Resolution + start_ra_contention_resolution_timer( + ra, + scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ra_ContentionResolutionTimer, + K2, + ra->UL_BWP.scs); + // reset state to wait msg3 ra->state = WAIT_Msg3; ra->Msg3_frame = sched_frame; @@ -1241,7 +1264,7 @@ static void nr_generate_Msg2(module_id_t module_idP, dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2 + sizeof(nfapi_nr_dl_tti_pdcch_pdu)); dl_req->nPDUs += 1; pdcch_pdu_rel15 = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; - nr_configure_pdcch(pdcch_pdu_rel15, coreset, false, &ra->sched_pdcch); + nr_configure_pdcch(pdcch_pdu_rel15, coreset, &ra->sched_pdcch); nr_mac->pdcch_pdu_idx[CC_id][coresetid] = pdcch_pdu_rel15; } @@ -1383,6 +1406,14 @@ static void nr_generate_Msg2(module_id_t module_idP, nr_get_Msg3alloc(module_idP, CC_id, scc, slotP, frameP, ra, nr_mac->tdd_beam_association); nr_add_msg3(module_idP, CC_id, frameP, slotP, ra, (uint8_t *) &tx_req->TLVs[0].value.direct[0]); + // Start RA contention resolution timer in Msg3 transmission slot (current slot + K2) + // 3GPP TS 38.321 Section 5.1.5 Contention Resolution + start_ra_contention_resolution_timer( + ra, + scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ra_ContentionResolutionTimer, + *ra->UL_BWP.tdaList_Common->list.array[ra->Msg3_tda_id]->k2, + ra->UL_BWP.scs); + if (ra->cfra) { NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[module_idP]->UE_info, ra->rnti); if (UE) { @@ -1458,7 +1489,7 @@ static void prepare_dl_pdus(gNB_MAC_INST *nr_mac, dl_tti_pdcch_pdu->PDUSize = (uint8_t)(2 + sizeof(nfapi_nr_dl_tti_pdcch_pdu)); dl_req->nPDUs += 1; pdcch_pdu_rel15 = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; - nr_configure_pdcch(pdcch_pdu_rel15, coreset, false, &ra->sched_pdcch); + nr_configure_pdcch(pdcch_pdu_rel15, coreset, &ra->sched_pdcch); nr_mac->pdcch_pdu_idx[CC_id][coresetid] = pdcch_pdu_rel15; } @@ -1884,9 +1915,9 @@ static void nr_check_Msg4_Ack(module_id_t module_id, int CC_id, frame_t frame, s if (harq->round == 0) { if (UE->Msg4_ACKed) { LOG_A(NR_MAC, "(UE RNTI 0x%04x) Received Ack of RA-Msg4. CBRA procedure succeeded!\n", ra->rnti); - UE->ra_timer = 0; } else { LOG_I(NR_MAC, "%4d.%2d UE %04x: RA Procedure failed at Msg4!\n", frame, slot, ra->rnti); + nr_mac_trigger_ul_failure(sched_ctrl, UE->current_DL_BWP.scs); } // Pause scheduling according to: @@ -2062,6 +2093,18 @@ void nr_schedule_RA(module_id_t module_idP, for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) { NR_RA_t *ra = &cc->ra[i]; LOG_D(NR_MAC, "RA[state:%d]\n", ra->state); + + // Check RA Contention Resolution timer + if (ra->state >= WAIT_Msg3) { + ra->contention_resolution_timer--; + if (ra->contention_resolution_timer < 0) { + LOG_W(NR_MAC, "(%d.%d) RA Contention Resolution timer expired for UE 0x%04x, RA procedure failed...\n", frameP, slotP, ra->rnti); + nr_mac_release_ue(mac, ra->rnti); + nr_clear_ra_proc(module_idP, CC_id, frameP, ra); + continue; + } + } + switch (ra->state) { case Msg2: nr_generate_Msg2(module_idP, CC_id, frameP, slotP, ra, DL_req, TX_req); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index c5b815a7e2..8227a78e01 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -405,7 +405,6 @@ static void nr_fill_nfapi_dl_sib1_pdu(int Mod_idP, nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; nr_configure_pdcch(pdcch_pdu_rel15, gNB_mac->sched_ctrlCommon->coreset, - true, // sib1 &gNB_mac->sched_ctrlCommon->sched_pdcch); nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs]; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 18e3ce1309..7d525e3894 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1023,7 +1023,7 @@ void nr_schedule_ue_spec(module_id_t module_id, pdcch_pdu = &dl_tti_pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15; LOG_D(NR_MAC,"Trying to configure DL pdcch for UE %04x, bwp %d, cs %d\n", UE->rnti, bwp_id, coresetid); NR_ControlResourceSet_t *coreset = sched_ctrl->coreset; - nr_configure_pdcch(pdcch_pdu, coreset, false, &sched_ctrl->sched_pdcch); + nr_configure_pdcch(pdcch_pdu, coreset, &sched_ctrl->sched_pdcch); gNB_mac->pdcch_pdu_idx[CC_id][coresetid] = pdcch_pdu; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 2022f46a5b..d2526c6c60 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -770,7 +770,6 @@ int nr_get_default_pucch_res(int pucch_ResourceCommon) { void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, NR_ControlResourceSet_t *coreset, - bool is_sib1, NR_sched_pdcch_t *pdcch) { @@ -794,10 +793,7 @@ void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, pdcch_pdu->ShiftIndex = pdcch->ShiftIndex; if(coreset->controlResourceSetId == 0) { - if(is_sib1) - pdcch_pdu->CoreSetType = NFAPI_NR_CSET_CONFIG_MIB_SIB1; - else - pdcch_pdu->CoreSetType = NFAPI_NR_CSET_CONFIG_PDCCH_CONFIG_CSET_0; + pdcch_pdu->CoreSetType = NFAPI_NR_CSET_CONFIG_MIB_SIB1; } else{ pdcch_pdu->CoreSetType = NFAPI_NR_CSET_CONFIG_PDCCH_CONFIG; } @@ -2401,10 +2397,6 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf /* Set default BWPs */ AssertFatal(UE->sc_info.n_ul_bwp <= NR_MAX_NUM_BWP, "uplinkBWP_ToAddModList has %d BWP!\n", UE->sc_info.n_ul_bwp); - if (get_softmodem_params()->phy_test == 0) { - UE->ra_timer = 12000 << UE->current_DL_BWP.scs; // 12000 ms is arbitrary and found to be a good timeout from experiments - } - /* get Number of HARQ processes for this UE */ // pdsch_servingcellconfig == NULL in SA -> will create default (8) number of HARQ processes create_dl_harq_list(sched_ctrl, &UE->sc_info); @@ -2959,24 +2951,6 @@ void nr_mac_update_timers(module_id_t module_id, if (sched_ctrl->rrc_processing_timer == 0) nr_mac_apply_cellgroup(mac, UE, frame, slot); } - - // RA timer - if (UE->ra_timer > 0) { - UE->ra_timer--; - if (UE->ra_timer == 0) { - const rnti_t rnti = UE->rnti; - LOG_W(NR_MAC, "Removing UE %04x because RA timer expired\n", rnti); - mac_remove_nr_ue(mac, rnti); - NR_COMMON_channels_t *cc = &mac->common_channels[0]; - for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) { - if (cc->ra[i].rnti == rnti) { - nr_clear_ra_proc(module_id, 0, frame, &cc->ra[i]); - } - } - // don't skip a UE, current UE does not exist anymore - UE--; - } - } } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index a812986d1f..da4a2b3f8c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -765,7 +765,6 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, nr_mac_reset_ul_failure(UE_scheduling_control); reset_dl_harq_list(UE_scheduling_control); reset_ul_harq_list(UE_scheduling_control); - UE_msg3_stage->ra_timer = 0; nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra); process_CellGroup(ra->CellGroup, UE_msg3_stage); @@ -2345,7 +2344,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot, n ul_dci_request_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); pdcch_pdu = &ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15; ul_dci_req->numPdus += 1; - nr_configure_pdcch(pdcch_pdu, coreset, false, &sched_ctrl->sched_pdcch); + nr_configure_pdcch(pdcch_pdu, coreset, &sched_ctrl->sched_pdcch); pdcch_pdu_coreset[coresetid] = pdcch_pdu; } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 0e9dae192f..f5f4d0beb1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -199,7 +199,6 @@ void find_search_space(int ss_type, void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, NR_ControlResourceSet_t *coreset, - bool is_sib1, NR_sched_pdcch_t *pdcch); NR_sched_pdcch_t set_pdcch_structure(gNB_MAC_INST *gNB_mac, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 042d17c899..2f550e642a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -223,6 +223,7 @@ typedef struct { NR_CellGroupConfig_t *CellGroup; /// Preambles for contention-free access NR_preamble_ue_t preambles; + int contention_resolution_timer; /// CFRA flag bool cfra; // BWP for RA @@ -712,7 +713,6 @@ typedef struct { // UE selected beam index uint8_t UE_beam_index; bool Msg4_ACKed; - uint32_t ra_timer; float ul_thr_ue; float dl_thr_ue; long pdsch_HARQ_ACK_Codebook; diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index f5e060e251..4a1295af9e 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -877,55 +877,57 @@ uint8_t do_NR_RRCReconfigurationComplete(uint8_t *buffer, size_t buffer_size, co return((enc_rval.encoded+7)/8); } -uint8_t do_RRCSetupComplete(uint8_t Mod_id, uint8_t *buffer, size_t buffer_size, - const uint8_t Transaction_id, uint8_t sel_plmn_id, const int dedicatedInfoNASLength, const char *dedicatedInfoNAS){ - asn_enc_rval_t enc_rval; - - NR_UL_DCCH_Message_t ul_dcch_msg; - NR_RRCSetupComplete_t *RrcSetupComplete; - memset((void *)&ul_dcch_msg,0,sizeof(NR_UL_DCCH_Message_t)); - - uint8_t buf[6]; +uint8_t do_RRCSetupComplete(uint8_t Mod_id, + uint8_t *buffer, + size_t buffer_size, + const uint8_t Transaction_id, + uint8_t sel_plmn_id, + const int dedicatedInfoNASLength, + const char *dedicatedInfoNAS) +{ + NR_UL_DCCH_Message_t ul_dcch_msg = {0}; ul_dcch_msg.message.present = NR_UL_DCCH_MessageType_PR_c1; ul_dcch_msg.message.choice.c1 = CALLOC(1,sizeof(struct NR_UL_DCCH_MessageType__c1)); ul_dcch_msg.message.choice.c1->present = NR_UL_DCCH_MessageType__c1_PR_rrcSetupComplete; ul_dcch_msg.message.choice.c1->choice.rrcSetupComplete = CALLOC(1, sizeof(NR_RRCSetupComplete_t)); - RrcSetupComplete = ul_dcch_msg.message.choice.c1->choice.rrcSetupComplete; - RrcSetupComplete->rrc_TransactionIdentifier = Transaction_id; - RrcSetupComplete->criticalExtensions.present = NR_RRCSetupComplete__criticalExtensions_PR_rrcSetupComplete; + NR_RRCSetupComplete_t *RrcSetupComplete = ul_dcch_msg.message.choice.c1->choice.rrcSetupComplete; + RrcSetupComplete->rrc_TransactionIdentifier = Transaction_id; + RrcSetupComplete->criticalExtensions.present = NR_RRCSetupComplete__criticalExtensions_PR_rrcSetupComplete; RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete = CALLOC(1, sizeof(NR_RRCSetupComplete_IEs_t)); - // RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete->nonCriticalExtension = CALLOC(1, - // sizeof(*RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete->nonCriticalExtension)); - RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete->selectedPLMN_Identity = sel_plmn_id; - RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete->registeredAMF = NULL; + NR_RRCSetupComplete_IEs_t *ies = RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete; + ies->selectedPLMN_Identity = sel_plmn_id; + ies->registeredAMF = NULL; - RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete->ng_5G_S_TMSI_Value = CALLOC(1, sizeof(struct NR_RRCSetupComplete_IEs__ng_5G_S_TMSI_Value)); - RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete->ng_5G_S_TMSI_Value->present = NR_RRCSetupComplete_IEs__ng_5G_S_TMSI_Value_PR_ng_5G_S_TMSI; - RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI.size = 6; - RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI.buf = buf; - RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI.buf[0] = 0x12; - RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI.buf[1] = 0x34; - RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI.buf[2] = 0x56; - RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI.buf[3] = 0x78; - RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI.buf[4] = 0x9A; - RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI.buf[5] = 0xBC; + ies->ng_5G_S_TMSI_Value = CALLOC(1, sizeof(struct NR_RRCSetupComplete_IEs__ng_5G_S_TMSI_Value)); + ies->ng_5G_S_TMSI_Value->present = NR_RRCSetupComplete_IEs__ng_5G_S_TMSI_Value_PR_ng_5G_S_TMSI; + NR_NG_5G_S_TMSI_t *stmsi = &ies->ng_5G_S_TMSI_Value->choice.ng_5G_S_TMSI; + stmsi->size = 6; + stmsi->buf = calloc(stmsi->size, sizeof(*stmsi->buf)); + AssertFatal(stmsi->buf != NULL, "out of memory\n"); + stmsi->buf[0] = 0x12; + stmsi->buf[1] = 0x34; + stmsi->buf[2] = 0x56; + stmsi->buf[3] = 0x78; + stmsi->buf[4] = 0x9A; + stmsi->buf[5] = 0xBC; - memset(&RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete->dedicatedNAS_Message,0,sizeof(OCTET_STRING_t)); - OCTET_STRING_fromBuf(&RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete->dedicatedNAS_Message,dedicatedInfoNAS,dedicatedInfoNASLength); + memset(&ies->dedicatedNAS_Message,0,sizeof(OCTET_STRING_t)); + OCTET_STRING_fromBuf(&ies->dedicatedNAS_Message, dedicatedInfoNAS, dedicatedInfoNASLength); if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { xer_fprint(stdout, &asn_DEF_NR_UL_DCCH_Message, (void *)&ul_dcch_msg); } - enc_rval = uper_encode_to_buffer(&asn_DEF_NR_UL_DCCH_Message, - NULL, - (void *)&ul_dcch_msg, - buffer, - buffer_size); + asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_UL_DCCH_Message, + NULL, + (void *)&ul_dcch_msg, + buffer, + buffer_size); AssertFatal(enc_rval.encoded > 0,"ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name,enc_rval.encoded); LOG_D(NR_RRC,"RRCSetupComplete Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_UL_DCCH_Message, &ul_dcch_msg); return((enc_rval.encoded+7)/8); } diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 98f67918d3..5ff35d4dc6 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -143,7 +143,7 @@ static void nr_rrc_ue_process_RadioBearerConfig(NR_UE_RRC_INST_t *ue_rrc, rnti_t rnti, rrcPerNB_t *rrcNB, NR_RadioBearerConfig_t *const radioBearerConfig); -static void nr_rrc_ue_generate_RRCSetupRequest(rnti_t rnti); +static void nr_rrc_ue_generate_RRCSetupRequest(NR_UE_RRC_INST_t *rrc, rnti_t rnti); static void nr_rrc_ue_generate_rrcReestablishmentComplete(NR_RRCReestablishment_t *rrcReestablishment); static void process_lte_nsa_msg(NR_UE_RRC_INST_t *rrc, nsa_msg_t *msg, int msg_len); static void nr_rrc_ue_process_rrcReconfiguration(const instance_t instance, @@ -229,12 +229,8 @@ static void nr_rrc_ue_process_rrcReconfiguration(const instance_t instance, } if (ie->measConfig != NULL) { LOG_I(NR_RRC, "Measurement Configuration is present\n"); - if (rrc->meas_config == NULL) { - rrc->meas_config = ie->measConfig; - } else { - // if some element need to be updated - nr_rrc_ue_process_measConfig(rrcNB, ie->measConfig); - } + // if some element need to be updated + nr_rrc_ue_process_measConfig(rrcNB, ie->measConfig); } if (ie->lateNonCriticalExtension != NULL) { // unuse now @@ -447,13 +443,14 @@ static void nr_rrc_ue_decode_NR_BCCH_BCH_Message(const instance_t instance, } int get_sib = 0; - if (get_softmodem_params()->sa && bcch_message->message.choice.mib->cellBarred == NR_MIB__cellBarred_notBarred) { + if (get_softmodem_params()->sa && + bcch_message->message.choice.mib->cellBarred == NR_MIB__cellBarred_notBarred && + NR_UE_rrc_inst[instance].nrRrcState != RRC_STATE_DETACH_NR) { NR_UE_RRC_SI_INFO *SI_info = &NR_UE_rrc_inst[instance].perNB[gNB_index].SInfo; // to schedule MAC to get SI if required get_sib = check_si_status(SI_info); } nr_rrc_mac_config_req_mib(instance, 0, bcch_message->message.choice.mib, get_sib); - bcch_message->message.choice.mib = NULL; ASN_STRUCT_FREE(asn_DEF_NR_BCCH_BCH_Message, bcch_message); return; } @@ -575,12 +572,12 @@ static int nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si) return 0; } -void nr_rrc_ue_generate_ra_msg(instance_t instance, RA_trigger_t trigger, rnti_t rnti) +void nr_rrc_ue_generate_ra_msg(NR_UE_RRC_INST_t *rrc, RA_trigger_t trigger, rnti_t rnti) { switch (trigger) { case INITIAL_ACCESS_FROM_RRC_IDLE: // After SIB1 is received, prepare RRCConnectionRequest - nr_rrc_ue_generate_RRCSetupRequest(rnti); + nr_rrc_ue_generate_RRCSetupRequest(rrc, rnti); break; case RRC_CONNECTION_REESTABLISHMENT: AssertFatal(1==0, "ra_trigger not implemented yet!\n"); @@ -609,8 +606,9 @@ void nr_rrc_ue_generate_ra_msg(instance_t instance, RA_trigger_t trigger, rnti_t } } -static void nr_rrc_ue_generate_RRCSetupRequest(rnti_t rnti) +static void nr_rrc_ue_generate_RRCSetupRequest(NR_UE_RRC_INST_t *rrc, rnti_t rnti) { + LOG_D(NR_RRC, "Generation of RRCSetupRequest\n"); uint8_t rv[6]; // Get RRCConnectionRequest, fill random for now // Generate random byte stream for contention resolution @@ -626,6 +624,10 @@ static void nr_rrc_ue_generate_RRCSetupRequest(rnti_t rnti) uint8_t buf[1024]; int len = do_RRCSetupRequest(buf, sizeof(buf), rv); + // start timer T300 + NR_UE_Timers_Constants_t *tac = &rrc->timers_and_constants; + tac->T300_active = true; + /* convention: RNTI for SRB0 is zero, as it changes all the time */ nr_rlc_srb_recv_sdu(rnti, 0, buf, len); } @@ -809,10 +811,6 @@ void nr_rrc_cellgroup_configuration(rrcPerNB_t *rrcNB, } } - if(cellGroupConfig->mac_CellGroupConfig != NULL) { - // TODO handle MAC CellGroupConfig - } - // TODO verify why we need this limitation if (get_softmodem_params()->sa || get_softmodem_params()->nsa) nr_rrc_manage_rlc_bearers(instance, cellGroupConfig, rrcNB, rrc->rnti); @@ -843,9 +841,7 @@ static void nr_rrc_ue_process_masterCellGroup(instance_t instance, xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig); } - nr_rrc_cellgroup_configuration(rrcNB, - instance, - cellGroupConfig); + nr_rrc_cellgroup_configuration(rrcNB, instance, cellGroupConfig); LOG_D(RRC,"Sending CellGroupConfig to MAC\n"); nr_rrc_mac_config_req_cg(instance, 0, cellGroupConfig); @@ -877,6 +873,58 @@ static void rrc_ue_generate_RRCSetupComplete(instance_t instance, rnti_t rnti, c nr_pdcp_data_req_srb(rnti, srb_id, 0, size, buffer, deliver_pdu_srb_rlc, NULL); } +static void nr_rrc_process_rrcsetup(const instance_t instance, + const rnti_t rnti, + const uint8_t gNB_index, + const NR_RRCSetup_t *rrcSetup) +{ + NR_UE_RRC_INST_t *rrc = &NR_UE_rrc_inst[instance]; + + // if the RRCSetup is received in response to an RRCReestablishmentRequest + // or RRCResumeRequest or RRCResumeRequest1 + // TODO none of the procedures implemented yet + + // perform the cell group configuration procedure in accordance with the received masterCellGroup + rrc->rnti = rnti; + nr_rrc_ue_process_masterCellGroup(instance, + rnti, + rrc->perNB + gNB_index, + &rrcSetup->criticalExtensions.choice.rrcSetup->masterCellGroup, + NULL); + // perform the radio bearer configuration procedure in accordance with the received radioBearerConfig + nr_rrc_ue_process_RadioBearerConfig(rrc, + rnti, + rrc->perNB + gNB_index, + &rrcSetup->criticalExtensions.choice.rrcSetup->radioBearerConfig); + + // TODO (not handled) if stored, discard the cell reselection priority information provided by + // the cellReselectionPriorities or inherited from another RAT + + // stop timer T300, T301 or T319 if running; + NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants; + timers->T300_active = false; + timers->T300_cnt = 0; + timers->T301_active = false; + timers->T301_cnt = 0; + timers->T319_active = false; + timers->T319_cnt = 0; + timers->T320_active = false; + timers->T320_cnt = 0; + + // TODO if T390 and T302 are running (not implemented) + + // if the RRCSetup is received in response to an RRCResumeRequest, RRCResumeRequest1 or RRCSetupRequest + // enter RRC_CONNECTED + rrc->nrRrcState = RRC_STATE_CONNECTED_NR; + + // set the content of RRCSetupComplete message + // TODO procedues described in 5.3.3.4 seems more complex than what we actualy do + rrc_ue_generate_RRCSetupComplete(instance, + rnti, + rrcSetup->rrc_TransactionIdentifier, + rrc->selected_plmn_identity); +} + static int8_t nr_rrc_ue_decode_ccch(const instance_t instance, const rnti_t rnti, const NRRrcMacCcchDataInd *ind, @@ -884,7 +932,7 @@ static int8_t nr_rrc_ue_decode_ccch(const instance_t instance, { NR_UE_RRC_INST_t *rrc = &NR_UE_rrc_inst[instance]; - NR_DL_CCCH_Message_t *dl_ccch_msg=NULL; + NR_DL_CCCH_Message_t *dl_ccch_msg = NULL; asn_dec_rval_t dec_rval; int rval=0; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_CCCH, VCD_FUNCTION_IN); @@ -915,28 +963,7 @@ static int8_t nr_rrc_ue_decode_ccch(const instance_t instance, case NR_DL_CCCH_MessageType__c1_PR_rrcSetup: LOG_I(NR_RRC, "[UE%ld][RAPROC] Logical Channel DL-CCCH (SRB0), Received NR_RRCSetup RNTI %x\n", instance, rnti); - - // Get configuration - // Release T300 timer - rrc->timers_and_constants.T300_active = 0; - rrc->rnti = rnti; - nr_rrc_ue_process_masterCellGroup( - instance, - rnti, - rrc->perNB + gNB_index, - &dl_ccch_msg->message.choice.c1->choice.rrcSetup->criticalExtensions.choice.rrcSetup->masterCellGroup, - NULL); - nr_rrc_ue_process_RadioBearerConfig( - rrc, - rnti, - rrc->perNB + gNB_index, - &dl_ccch_msg->message.choice.c1->choice.rrcSetup->criticalExtensions.choice.rrcSetup->radioBearerConfig); - rrc->nrRrcState = RRC_STATE_CONNECTED_NR; - - rrc_ue_generate_RRCSetupComplete(instance, - rnti, - dl_ccch_msg->message.choice.c1->choice.rrcSetup->rrc_TransactionIdentifier, - rrc->selected_plmn_identity); + nr_rrc_process_rrcsetup(instance, rnti, gNB_index, dl_ccch_msg->message.choice.c1->choice.rrcSetup); rval = 0; break; @@ -947,6 +974,7 @@ static int8_t nr_rrc_ue_decode_ccch(const instance_t instance, } } + ASN_STRUCT_FREE(asn_DEF_NR_DL_CCCH_Message, dl_ccch_msg); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_CCCH, VCD_FUNCTION_OUT); return rval; } @@ -1418,37 +1446,36 @@ void *rrc_nrue(void *notUsed) itti_receive_msg(TASK_RRC_NRUE, &msg_p); instance_t instance = ITTI_MSG_DESTINATION_INSTANCE(msg_p); NR_UE_RRC_INST_t *rrc = &NR_UE_rrc_inst[instance]; - + LOG_D(NR_RRC, "[UE %ld] Received %s\n", instance, ITTI_MSG_NAME(msg_p)); - + switch (ITTI_MSG_ID(msg_p)) { case TERMINATE_MESSAGE: LOG_W(NR_RRC, " *** Exiting RRC thread\n"); itti_exit_task(); break; - + case MESSAGE_TEST: break; - + case NR_RRC_MAC_SYNC_IND: { nr_sync_msg_t sync_msg = NR_RRC_MAC_SYNC_IND(msg_p).in_sync ? IN_SYNC : OUT_OF_SYNC; NR_UE_Timers_Constants_t *tac = &rrc->timers_and_constants; handle_rlf_sync(tac, sync_msg); } break; - + case NRRRC_FRAME_PROCESS: LOG_D(NR_RRC, "Received %s: frame %d\n", ITTI_MSG_NAME(msg_p), NRRRC_FRAME_PROCESS(msg_p).frame); // increase the timers every 10ms (every new frame) - NR_UE_Timers_Constants_t *timers = &NR_UE_rrc_inst[instance].timers_and_constants; - nr_rrc_handle_timers(timers); + nr_rrc_handle_timers(rrc, instance); NR_UE_RRC_SI_INFO *SInfo = &NR_UE_rrc_inst[instance].perNB[NRRRC_FRAME_PROCESS(msg_p).gnb_id].SInfo; nr_rrc_SI_timers(SInfo); break; - + case NR_RRC_MAC_MSG3_IND: - nr_rrc_ue_generate_ra_msg(instance, INITIAL_ACCESS_FROM_RRC_IDLE, NR_RRC_MAC_MSG3_IND(msg_p).rnti); + nr_rrc_ue_generate_ra_msg(rrc, INITIAL_ACCESS_FROM_RRC_IDLE, NR_RRC_MAC_MSG3_IND(msg_p).rnti); break; - + case NR_RRC_MAC_RA_IND: LOG_D(NR_RRC, "[UE %ld] Received %s: frame %d RA %s\n", @@ -1458,7 +1485,7 @@ void *rrc_nrue(void *notUsed) NR_RRC_MAC_RA_IND(msg_p).RA_succeeded ? "successful" : "failed"); nr_rrc_handle_ra_indication(rrc, NR_RRC_MAC_RA_IND(msg_p).RA_succeeded); break; - + case NR_RRC_MAC_BCCH_DATA_IND: LOG_D(NR_RRC, "[UE %ld] Received %s: gNB %d\n", instance, ITTI_MSG_NAME(msg_p), NR_RRC_MAC_BCCH_DATA_IND(msg_p).gnb_index); NRRrcMacBcchDataInd *bcch = &NR_RRC_MAC_BCCH_DATA_IND(msg_p); @@ -1467,13 +1494,12 @@ void *rrc_nrue(void *notUsed) else nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message(instance, bcch->gnb_index, bcch->sdu, bcch->sdu_size, bcch->rsrq, bcch->rsrp); break; - + case NR_RRC_MAC_CCCH_DATA_IND: { NRRrcMacCcchDataInd *ind = &NR_RRC_MAC_CCCH_DATA_IND(msg_p); nr_rrc_ue_decode_ccch(instance, ind->rnti, ind, 0); } break; - - /* PDCP messages */ + case NR_RRC_DCCH_DATA_IND: nr_rrc_ue_decode_dcch(instance, NR_RRC_DCCH_DATA_IND(msg_p).rnti, @@ -1482,11 +1508,19 @@ void *rrc_nrue(void *notUsed) NR_RRC_DCCH_DATA_IND(msg_p).sdu_size, NR_RRC_DCCH_DATA_IND(msg_p).gNB_index); break; - + case NAS_KENB_REFRESH_REQ: memcpy(rrc->kgnb, NAS_KENB_REFRESH_REQ(msg_p).kenb, sizeof(rrc->kgnb)); break; - + + case NAS_DETACH_REQ: + if (!NAS_DETACH_REQ(msg_p).wait_release) { + rrc->nrRrcState = RRC_STATE_DETACH_NR; + NR_Release_Cause_t release_cause = OTHER; + nr_rrc_going_to_IDLE(instance, release_cause, NULL); + } + break; + case NAS_UPLINK_DATA_REQ: { uint32_t length; uint8_t *buffer; @@ -1500,7 +1534,7 @@ void *rrc_nrue(void *notUsed) nr_pdcp_data_req_srb(rrc->rnti, srb_id, 0, length, buffer, deliver_pdu_srb_rlc, NULL); break; } - + default: LOG_E(NR_RRC, "[UE %ld] Received unexpected message %s\n", instance, ITTI_MSG_NAME(msg_p)); break; @@ -1915,9 +1949,6 @@ void nr_rrc_going_to_IDLE(instance_t instance, } } - asn1cFreeStruc(asn_DEF_NR_MeasConfig, rrc->meas_config); - rrc->meas_config = NULL; - for (int i = 0; i < NB_CNX_UE; i++) { rrcPerNB_t *nb = &rrc->perNB[i]; NR_UE_RRC_SI_INFO *SI_info = &nb->SInfo; @@ -1938,11 +1969,14 @@ void nr_rrc_going_to_IDLE(instance_t instance, } // reset MAC - NR_UE_MAC_reset_cause_t cause = GO_TO_IDLE; + NR_UE_MAC_reset_cause_t cause = (rrc->nrRrcState == RRC_STATE_DETACH_NR) ? DETACH : GO_TO_IDLE; nr_rrc_mac_config_req_reset(instance, cause); // enter RRC_IDLE - rrc->nrRrcState = RRC_STATE_IDLE_NR; + LOG_I(NR_RRC, "RRC moved into IDLE state\n"); + if (rrc->nrRrcState != RRC_STATE_DETACH_NR) + rrc->nrRrcState = RRC_STATE_IDLE_NR; + rrc->rnti = 0; // Indicate the release of the RRC connection to upper layers @@ -1951,6 +1985,15 @@ void nr_rrc_going_to_IDLE(instance_t instance, itti_send_msg_to_task(TASK_NAS_NRUE, instance, msg_p); } +void handle_t300_expiry(instance_t instance) +{ + // reset MAC, release the MAC configuration + NR_UE_MAC_reset_cause_t cause = T300_EXPIRY; + nr_rrc_mac_config_req_reset(instance, cause); + // TODO handle connEstFailureControl + // TODO inform upper layers about the failure to establish the RRC connection +} + void nr_ue_rrc_timer_trigger(int instance, int frame, int gnb_id) { MessageDef *message_p; diff --git a/openair2/RRC/NR_UE/rrc_defs.h b/openair2/RRC/NR_UE/rrc_defs.h index 4266716799..768d4caf1a 100644 --- a/openair2/RRC/NR_UE/rrc_defs.h +++ b/openair2/RRC/NR_UE/rrc_defs.h @@ -83,7 +83,7 @@ typedef enum Rrc_State_NR_e { RRC_STATE_IDLE_NR = 0, RRC_STATE_INACTIVE_NR, RRC_STATE_CONNECTED_NR, - + RRC_STATE_DETACH_NR, RRC_STATE_FIRST_NR = RRC_STATE_IDLE_NR, RRC_STATE_LAST_NR = RRC_STATE_CONNECTED_NR, } Rrc_State_NR_t; @@ -206,8 +206,6 @@ typedef struct rrcPerNB { } rrcPerNB_t; typedef struct NR_UE_RRC_INST_s { - NR_MeasConfig_t *meas_config; - rrcPerNB_t perNB[NB_CNX_UE]; char *uecap_file; diff --git a/openair2/RRC/NR_UE/rrc_proto.h b/openair2/RRC/NR_UE/rrc_proto.h index 1b4df0d797..08db8f6506 100644 --- a/openair2/RRC/NR_UE/rrc_proto.h +++ b/openair2/RRC/NR_UE/rrc_proto.h @@ -105,7 +105,7 @@ void nr_mac_rrc_msg3_ind(const module_id_t mod_id, int rnti); void *rrc_nrue_task(void *args_p); void *rrc_nrue(void *args_p); -void nr_rrc_handle_timers(NR_UE_Timers_Constants_t *timers); +void nr_rrc_handle_timers(NR_UE_RRC_INST_t *rrc, instance_t instance); /**\brief RRC NSA UE task. \param void *args_p Pointer on arguments to start the task. */ @@ -122,6 +122,7 @@ int get_from_lte_ue_fd(); void nr_rrc_SI_timers(NR_UE_RRC_SI_INFO *SInfo); void nr_ue_rrc_timer_trigger(int module_id, int frame, int gnb_id); +void handle_t300_expiry(instance_t instance); void reset_rlf_timers_and_constants(NR_UE_Timers_Constants_t *tac); void set_default_timers_and_constants(NR_UE_Timers_Constants_t *tac); diff --git a/openair2/RRC/NR_UE/rrc_timers_and_constants.c b/openair2/RRC/NR_UE/rrc_timers_and_constants.c index 0a7010850d..5b4823d03d 100644 --- a/openair2/RRC/NR_UE/rrc_timers_and_constants.c +++ b/openair2/RRC/NR_UE/rrc_timers_and_constants.c @@ -98,9 +98,18 @@ void nr_rrc_SI_timers(NR_UE_RRC_SI_INFO *SInfo) } } -void nr_rrc_handle_timers(NR_UE_Timers_Constants_t *timers) +void nr_rrc_handle_timers(NR_UE_RRC_INST_t *rrc, instance_t instance) { - // T304 + NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants; + + if (timers->T300_active == true) { + timers->T300_cnt += 10; + if(timers->T300_cnt >= timers->T300_k) { + timers->T300_active = false; + timers->T300_cnt = 0; + handle_t300_expiry(instance); + } + } if (timers->T304_active == true) { timers->T304_cnt += 10; if(timers->T304_cnt >= timers->T304_k) { @@ -120,6 +129,14 @@ void nr_rrc_handle_timers(NR_UE_Timers_Constants_t *timers) AssertFatal(false, "Radio link failure! Not handled yet!\n"); } } + if (timers->T311_active == true) { + timers->T311_cnt += 10; + if(timers->T311_cnt >= timers->T311_k) { + // Upon T311 expiry, the UE shall perform the actions upon going to RRC_IDLE + // with release cause 'RRC connection failure' + nr_rrc_going_to_IDLE(instance, RRC_CONNECTION_FAILURE, NULL); + } + } } void nr_rrc_set_T304(NR_UE_Timers_Constants_t *tac, NR_ReconfigurationWithSync_t *reconfigurationWithSync) diff --git a/openair3/NAS/COMMON/EMM/MSG/RegistrationAccept.c b/openair3/NAS/COMMON/EMM/MSG/RegistrationAccept.c index c34d777bd5..d7c5c5d719 100644 --- a/openair3/NAS/COMMON/EMM/MSG/RegistrationAccept.c +++ b/openair3/NAS/COMMON/EMM/MSG/RegistrationAccept.c @@ -39,7 +39,7 @@ #include "RegistrationAccept.h" #include "assertions.h" -int decode_registration_accept(registration_accept_msg *registration_accept, uint8_t *buffer, uint32_t len) +int decode_registration_accept(registration_accept_msg *registration_accept, const uint8_t *buffer, uint32_t len) { uint32_t decoded = 0; int decoded_result = 0; diff --git a/openair3/NAS/COMMON/EMM/MSG/RegistrationAccept.h b/openair3/NAS/COMMON/EMM/MSG/RegistrationAccept.h index e0d3ade23a..30c434c662 100644 --- a/openair3/NAS/COMMON/EMM/MSG/RegistrationAccept.h +++ b/openair3/NAS/COMMON/EMM/MSG/RegistrationAccept.h @@ -62,7 +62,7 @@ typedef struct registration_accept_msg_tag { FGSMobileIdentity *guti; } registration_accept_msg; -int decode_registration_accept(registration_accept_msg *registrationaccept, uint8_t *buffer, uint32_t len); +int decode_registration_accept(registration_accept_msg *registrationaccept, const uint8_t *buffer, uint32_t len); int encode_registration_accept(registration_accept_msg *registrationaccept, uint8_t *buffer, uint32_t len); diff --git a/openair3/NAS/COMMON/IES/FGSMobileIdentity.c b/openair3/NAS/COMMON/IES/FGSMobileIdentity.c index ea877481e6..c0b60f101f 100644 --- a/openair3/NAS/COMMON/IES/FGSMobileIdentity.c +++ b/openair3/NAS/COMMON/IES/FGSMobileIdentity.c @@ -37,13 +37,13 @@ #include "TLVDecoder.h" #include "FGSMobileIdentity.h" -static int decode_guti_5gs_mobile_identity(Guti5GSMobileIdentity_t *guti, uint8_t *buffer); +static int decode_guti_5gs_mobile_identity(Guti5GSMobileIdentity_t *guti, const uint8_t *buffer); static int encode_guti_5gs_mobile_identity(Guti5GSMobileIdentity_t *guti, uint8_t *buffer); static int encode_suci_5gs_mobile_identity(Suci5GSMobileIdentity_t *suci, uint8_t *buffer); static int encode_imeisv_5gs_mobile_identity(Imeisv5GSMobileIdentity_t *imeisv, uint8_t *buffer); -int decode_5gs_mobile_identity(FGSMobileIdentity *fgsmobileidentity, uint8_t iei, uint8_t *buffer, uint32_t len) +int decode_5gs_mobile_identity(FGSMobileIdentity *fgsmobileidentity, uint8_t iei, const uint8_t *buffer, uint32_t len) { int decoded_rc = TLV_DECODE_VALUE_DOESNT_MATCH; int decoded = 0; @@ -117,7 +117,7 @@ int encode_5gs_mobile_identity(FGSMobileIdentity *fgsmobileidentity, uint8_t iei return (encoded + encoded_rc); } -static int decode_guti_5gs_mobile_identity(Guti5GSMobileIdentity_t *guti, uint8_t *buffer) +static int decode_guti_5gs_mobile_identity(Guti5GSMobileIdentity_t *guti, const uint8_t *buffer) { int decoded = 0; uint16_t temp; diff --git a/openair3/NAS/COMMON/IES/FGSMobileIdentity.h b/openair3/NAS/COMMON/IES/FGSMobileIdentity.h index 82d943fd19..9356a46eff 100644 --- a/openair3/NAS/COMMON/IES/FGSMobileIdentity.h +++ b/openair3/NAS/COMMON/IES/FGSMobileIdentity.h @@ -149,7 +149,7 @@ typedef union FGSMobileIdentity_tag { int encode_5gs_mobile_identity(FGSMobileIdentity *fgsmobileidentity, uint8_t iei, uint8_t *buffer, uint32_t len); -int decode_5gs_mobile_identity(FGSMobileIdentity *fgsmobileidentity, uint8_t iei, uint8_t *buffer, uint32_t len); +int decode_5gs_mobile_identity(FGSMobileIdentity *fgsmobileidentity, uint8_t iei, const uint8_t *buffer, uint32_t len); #endif /* FGS MOBILE IDENTITY_H_ */ diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index 4b7c4cc45c..d73e95b030 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -617,7 +617,7 @@ static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initia } } -static void decodeRegistrationAccept(uint8_t *buf, int len, nr_ue_nas_t *nas) +static void decodeRegistrationAccept(const uint8_t *buf, int len, nr_ue_nas_t *nas) { registration_accept_msg reg_acc = {0}; /* it seems there is no 5G corresponding emm_msg_decode() function, so here @@ -911,6 +911,14 @@ static void send_nas_uplink_data_req(instance_t instance, const as_nas_info_t *i itti_send_msg_to_task(TASK_RRC_NRUE, instance, msg); } +static void send_nas_detach_req(instance_t instance, bool wait_release) +{ + MessageDef *msg = itti_alloc_new_message(TASK_NAS_NRUE, 0, NAS_DETACH_REQ); + nas_detach_req_t *req = &NAS_DETACH_REQ(msg); + req->wait_release = wait_release; + itti_send_msg_to_task(TASK_RRC_NRUE, instance, msg); +} + static void parse_allowed_nssai(nr_nas_msg_snssai_t nssaiList[8], const uint8_t *buf, const uint32_t len) { int nssai_cnt = 0; @@ -1033,6 +1041,29 @@ void *nas_nrue_task(void *args_p) } } +static void handle_registration_accept(instance_t instance, + nr_ue_nas_t *nas, + const uint8_t *pdu_buffer, + uint32_t msg_length) +{ + LOG_I(NAS, "[UE] Received REGISTRATION ACCEPT message\n"); + decodeRegistrationAccept(pdu_buffer, msg_length, nas); + get_allowed_nssai(nas_allowed_nssai, pdu_buffer, msg_length); + + as_nas_info_t initialNasMsg = {0}; + generateRegistrationComplete(nas, &initialNasMsg, NULL); + if (initialNasMsg.length > 0) { + send_nas_uplink_data_req(instance, &initialNasMsg); + LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message(RegistrationComplete)\n"); + } + const int nssai_idx = get_user_nssai_idx(nas_allowed_nssai, nas); + if (nssai_idx < 0) { + LOG_E(NAS, "NSSAI parameters not match with allowed NSSAI. Couldn't request PDU session.\n"); + } else { + request_default_pdusession(instance, nssai_idx); + } +} + void *nas_nrue(void *args_p) { // Wait for a message or an event @@ -1112,24 +1143,8 @@ void *nas_nrue(void *args_p) int msg_type = get_msg_type(pdu_buffer, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length); if (msg_type == REGISTRATION_ACCEPT) { - LOG_I(NAS, "[UE] Received REGISTRATION ACCEPT message\n"); nr_ue_nas_t *nas = get_ue_nas_info(0); - decodeRegistrationAccept(pdu_buffer, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length, nas); - get_allowed_nssai(nas_allowed_nssai, pdu_buffer, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length); - - as_nas_info_t initialNasMsg = {0}; - generateRegistrationComplete(nas, &initialNasMsg, NULL); - if (initialNasMsg.length > 0) { - send_nas_uplink_data_req(instance, &initialNasMsg); - LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message(RegistrationComplete)\n"); - } - - const int nssai_idx = get_user_nssai_idx(nas_allowed_nssai, nas); - if (nssai_idx < 0) { - LOG_E(NAS, "NSSAI parameters not match with allowed NSSAI. Couldn't request PDU session.\n"); - } else { - request_default_pdusession(instance, nssai_idx); - } + handle_registration_accept(instance, nas, pdu_buffer, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length); } else if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) { capture_pdu_session_establishment_accept_msg(pdu_buffer, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length); } @@ -1165,15 +1180,19 @@ void *nas_nrue(void *args_p) case NAS_DEREGISTRATION_REQ: { LOG_I(NAS, "[UE %ld] Received %s\n", instance, ITTI_MSG_NAME(msg_p)); nr_ue_nas_t *nas = get_ue_nas_info(0); + nas_deregistration_req_t *req = &NAS_DEREGISTRATION_REQ(msg_p); if (nas->guti) { - nas_deregistration_req_t *req = &NAS_DEREGISTRATION_REQ(msg_p); - if (req->cause == AS_DETACH) + if (req->cause == AS_DETACH) { nas->termination_procedure = true; + send_nas_detach_req(instance, true); + } as_nas_info_t initialNasMsg = {0}; generateDeregistrationRequest(nas, &initialNasMsg, req); send_nas_uplink_data_req(instance, &initialNasMsg); } else { - LOG_E(NAS, "no GUTI, cannot trigger deregistration request\n"); + LOG_W(NAS, "No GUTI, cannot trigger deregistration request.\n"); + if (req->cause == AS_DETACH) + send_nas_detach_req(instance, false); } } break; @@ -1205,21 +1224,7 @@ void *nas_nrue(void *args_p) decodeDownlinkNASTransport(&initialNasMsg, pdu_buffer); break; case REGISTRATION_ACCEPT: - LOG_I(NAS, "[UE] Received REGISTRATION ACCEPT message\n"); - decodeRegistrationAccept(pdu_buffer, NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length, nas); - - as_nas_info_t initialNasMsg = {0}; - generateRegistrationComplete(nas, &initialNasMsg, NULL); - if (initialNasMsg.length > 0) { - send_nas_uplink_data_req(instance, &initialNasMsg); - LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message(RegistrationComplete)\n"); - } - const int nssai_idx = get_user_nssai_idx(nas_allowed_nssai, nas); - if (nssai_idx < 0) { - LOG_E(NAS, "NSSAI parameters not match with allowed NSSAI. Couldn't request PDU session.\n"); - } else { - request_default_pdusession(instance, nssai_idx); - } + handle_registration_accept(instance, nas, pdu_buffer, NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length); break; case FGS_DEREGISTRATION_ACCEPT: LOG_I(NAS, "received deregistration accept\n"); diff --git a/radio/rfsimulator/README.md b/radio/rfsimulator/README.md index 1974e55f50..4b33860809 100644 --- a/radio/rfsimulator/README.md +++ b/radio/rfsimulator/README.md @@ -1,65 +1,66 @@ +[[_TOC_]] + # General -This is an RF simulator that allows to test OAI without an RF board. It replaces an actual RF board driver. -As much as possible, it works like an RF board, but not in real-time: It can run faster than real-time if there is enough CPU, or slower (it is CPU-bound instead of real-time RF sampling-bound). +This is an RF simulator that allows to test OAI without an RF board. It +replaces an actual RF board driver. In other words, towards the xNB/UE, it +behaves like a "real" RF board, but it forwards samples between both ends +instead of sending it over the air. It can simulate simple channels, such as +AWGN, hence it *simulates* RF. -It can be run either in: +As much as possible, it works like an RF board, but not in real-time: It can +run faster than real-time if there is enough CPU, or slower (it is CPU-bound +instead of real-time RF sampling-bound). -- "noS1" mode: the generated IP traffic is sent and received between gNB and UE IP tunnel interfaces ("oaitun") by applications like ping and iperf -- "phy-test" mode: random UL and DL traffic is generated at every scheduling opportunity - - -# build +# Build ## From [build_oai](../../../doc/BUILD.md) script The RF simulator is implemented as an OAI device and always built when you build the OAI eNB or the OAI UE. -Using the `-w SIMU` option it is possible to just re-build the RF simulator device. +Using the `-w SIMU` option it is possible to just re-build the RF simulator device. Example: ```bash -./build_oai --UE --eNB -Will compile UE -Will compile eNB -CMAKE_CMD=cmake .. -No local radio head and no transport protocol selected -No radio head has been selected (HW set to None) -No transport protocol has been selected (TP set to None) -RF HW set to None -Flags for Deadline scheduler: False -...................... -...................... -Compiling rfsimulator -Log file for compilation has been written to: /usr/local/oai/rfsimu_config/openairinterface5g/cmake_targets/log/rfsimulator.txt -rfsimulator compiled -...................... -...................... +./build_oai --UE --eNB --gNB --nrUE --ninja -w SIMU ``` ## Add the rfsimulator after initial build + After any regular build you can compile the device from the build directory: ```bash cd /openairinterface5g/cmake_targets/ran_build/build -make rfsimulator +ninja rfsimulator ``` + This is equivalent to using `-w SIMU` when running the `build_oai` script. # Usage -To use the RF simulator add the `--rfsim` option to the command line. By default the RF simulator device will try to connect to host 127.0.0.1, port 4043, which is usually the behavior for the UE. + +## Overview + +To use the RF simulator add the `--rfsim` option to the command line. By +default the RF simulator device will try to connect to host 127.0.0.1, port +4043, which is usually the behavior for the UE. For the eNB/gNB, you either +have to pass `--rfsimulator.serveraddr server` on the command line, or specify +the corresponding section in the configuration file. The RF simulator is using the configuration module, and its parameters are defined in a specific section called "rfsimulator". | parameter | usage | default | |:---------------------|:------------------------------------------------------------------------------------------------------------------|----:| -| serveraddr | ip address to connect to, or "enb" to behave as a tcp server | 127.0.0.1 | +| serveraddr | ip address to connect to, or `server` to behave as a tcp server | 127.0.0.1 | | serverport | port number to connect to or to listen on (eNB, which behaves as a tcp server) | 4043 | | options | list of comma separated run-time options, two are supported: `chanmod` to enable channel modeling and `saviq` to write transmitted iqs to a file | all options disabled | | modelname | Name of the channel model to apply on received iqs when the `chanmod` option is enabled | AWGN | | IQfile | Path to the file to be used to store iqs, when the `saviq` option is enabled | /tmp/rfsimulator.iqs | - + ## How to use the RF simulator options -To define and use a channel model, the configuration file needs to include a channel configuration file. To do this, add `@include "channelmod_rfsimu.conf"` to the end of the configuration file, and place the channel configuration file in the same directory. An example channel configuration file `channelmod_rfsimu.conf` is in `ci-scripts/conf_files`. +To define and use a channel model, the configuration file needs to include a +channel configuration file. To do this, add `@include "channelmod_rfsimu.conf"` +to the end of the configuration file, and place the channel configuration file +in the same directory. An example channel configuration file is +[`ci-scripts/conf_files/channelmod_rfsimu.conf`](../../ci-scripts/conf_files/channelmod_rfsimu.conf). Add the following options to the command line to enable the channel model and the IQ samples saving for future replay: ```bash @@ -69,7 +70,7 @@ or just: ```bash --rfsimulator.options chanmod ``` -to enable the channel model. +to enable the channel model. set the model with: ```bash @@ -86,16 +87,26 @@ where `@include "channelmod_rfsimu.conf"` has been added at the end of the file, ## 4G case -For the UE, it should be set to the IP address of the eNB. For example: +For the eNB, use a valid configuration file setup for the USRP board tests and start the softmodem with the `--rfsim` and `--rfsimulator.serveraddr server` options. ```bash -sudo ./lte-uesoftmodem -C 2685000000 -r 50 --rfsimulator.serveraddr 192.168.2.200 +sudo ./lte-softmodem -O --rfsim --rfsimulator.serveraddr server ``` -For the eNB, use a valid configuration file setup for the USRP board tests and start the softmodem as usual, **but**, adding the `--rfsim` option. -```bash -sudo ./lte-softmodem -O --rfsim +Often, configuration files define the corresponding `rfsimulator` section, in +which case you might omit `--rfsimulator.serveraddr server`. Example: +``` +rfsimulator : { + serveraddr = "server"; +}; ``` -Except this, the UE and the eNB can be used as if the RF is real. noS1 mode can also be used with the RF simulator. +For the UE, it should be set to the IP address of the eNB. For instance, if the +eNB runs on another host with IP `192.168.2.200`, do +```bash +sudo ./lte-uesoftmodem -C 2685000000 -r 50 --rfsim --rfsimulator.serveraddr 192.168.2.200 +``` +For running on the same host, only `--rfsim` is necessary. + +The UE and the eNB can be used as if the RF is real. The noS1 mode might be used as well with the RF simulator. If you reach 'RA not active' on UE, be careful to generate a valid SIM. ```bash @@ -104,52 +115,30 @@ $OPENAIR_DIR/cmake_targets/ran_build/build/conf2uedata -c $OPENAIR_DIR/openair3/ ## 5G case -If `build_oai` has not been run with `-w SIMU`, you need to build the `rfsimulator` manually. To do so: +Similarly as for 4G, first launch the gNB, here in an example for the phytest: + ```bash -cd ran_build/build -make rfsimulator +sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf --gNBs.[0].min_rxtxtime 6 --phy-test --rfsim --rfsimulator.serveraddr server ``` -### Launch gNB in one window +`--gNBs.[0].min_rxtxtime 6` is due to the UE not being able to handle shorter +RX/TX times. As in the 4G case above, you can define an `rfsimulator` section +in the config file. + +Then, launch the UE: ```bash -sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf --parallel-config PARALLEL_SINGLE_THREAD --rfsim --phy-test -``` - -### Launch UE in another window - -```bash -sudo ./nr-uesoftmodem --rfsim --phy-test --rfsimulator.serveraddr +sudo ./nr-uesoftmodem --rfsim --phy-test --rfsimulator.serveraddr ``` Notes: 1. This starts the gNB and UE in the `phy-test` UP-only mode where the gNB is started as if a UE had already connected. See [RUNMODEM.md](../../doc/RUNMODEM.md) for more details. -2. can be 127.0.0.1 if both gNB and nrUE executables run on the same host, OR the IP interface address of the remote host running the gNB executable, if the gNB and nrUE run on separate hosts. +2. `` should be the IP interface address of the remote host running the gNB executable, if the gNB and nrUE run on separate hosts, or be omitted if they are on the same host. 3. To enable the noS1 mode, `--noS1` option should be added to the command line, see again [RUNMODEM.md](../../doc/RUNMODEM.md). 4. To operate the gNB/UE with a 5GC, start them using the `--sa` option. More information can be found [here](../../../doc/NR_SA_Tutorial_OAI_CN5G.md). -In the UE, you can add `-d` option to get the softscope. - -### Testing IP traffic (ping and iperf) - -``` -ping -I oaitun_enb1 10.0.1.2 (from gNB mchine) -ping -I oaitun_ue1 10.0.1.1 (from nrUE mchine) -``` - -```iperf (Downlink): -Server nrUE machine: iperf -s -i 1 -u -B 10.0.1.2 -Client gNB machine: iperf -c 10.0.1.2 -u -b 0.1M --bind 10.0.1.1 -``` - -```iperf (Uplink): -Server gNB machine: iperf -s -i 1 -u -B 10.0.1.1 -Client nrUE machine: iperf -c 10.0.1.1 -u -b 0.1M --bind 10.0.1.2 -Note: iperf tests can be performed only when running gNB and nrUE on separate hosts. -``` - -### Store and replay +## Store and replay You can store emitted I/Q samples. If you set the option `saviq`, the simulator will write all the I/Q samples into this file. Then, you can replay with the executable `replay_node`. @@ -163,7 +152,7 @@ The file format is successive blocks of a header followed by the I/Q array. If y The format intends to be compatible with the OAI store/replay feature on USRP. -### Channel simulation +## Channel simulation When the `chanmod` option is enabled, the RF channel simulator is called. @@ -221,11 +210,8 @@ setting the pathloss, etc...: channelmod modify channelmod modify 0 ploss 15 ``` -where: -```bash - can be one of "riceanf", "aoa", "randaoa", "ploss", "offset", "forgetf" -``` +where `` can be one of `riceanf`, `aoa`, `randaoa`, `ploss`, `offset`, `forgetf`. # Caveats -Still issues in power control: txgain, rxgain are not used. +There are issues in power control: txgain/rxgain setting is not supported.