diff --git a/doc/L1SIM.md b/doc/L1SIM.md index 7e6d893a2ec2a3f7df7130a96149632f4265b5dd..56be7f93b6b571a72db016e3918c5edd97c4a5ed 100644 --- a/doc/L1SIM.md +++ b/doc/L1SIM.md @@ -12,23 +12,29 @@ </tr> </table> -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. -[[_TOC_]] - -The old oaisim is dead! Long live oaisim! :) +Context: oaisim used to be a simulation mode inside OAI to emulate an eNB and +multiple UEs. -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). +[[_TOC_]] -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. +# Build -# <a name="build">[How to build the eNB and the UE](BUILD.md)</a> +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 +``` -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 -# <a name="run-noS1-eNB">How to run an eNB with the noS1 option</a> +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 ``` -# <a name="run-noS1-UE">How to run a UE with the noS1 option</a> +# 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. -# <a name="CInote">Continuous Integration notes</a> -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. - -# <a name="noS1-pinging">How to ping an eNB from a UE and vice versa (with the noS1 option)</a> +# 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 6339d7fb5f3dff5627bce7c175a47d74f8d531f9..e3790114a392b85a44d185870d3b695cdbbf123c 100644 --- a/doc/RUNMODEM.md +++ b/doc/RUNMODEM.md @@ -7,12 +7,18 @@ </a> </td> <td style="border-collapse: collapse; border: none; vertical-align: center;"> - <b><font size = "5">Running OAI Softmodems</font></b> + <b><font size = "5">Running OAI 5G Softmodems</font></b> </td> </tr> </table> -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. - -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.** +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). -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 0ff60d4d4fabf06a3122cc8355c6163b5cfa2bfc..20c1e890bc8fb709cda571b761edf77099682f81 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 84825747ec2ed413d596012340b5bfaf80e5e964..36e71b2a329023c5ece73fc87e16c6fc7481a373 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); - - 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; - - case 'd': - SNRinc = atof(optarg); - break; - - case 'f': - SNRstop = atof(optarg); - break; - - case 'l': - messageLength = atoi(optarg); - break; - - case 'i': - iterations = atoi(optarg); - break; - - /*case 'm': - matlabDebug = 1; - //#define DEBUG_POLAR_MATLAB - 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); - - 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); - - 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((uint16_t*)&testInput, (uint8_t)messageLength); - stop_meas(&timeEncoder); - - for (int i=0; i<NR_SMALL_BLOCK_CODED_BITS; i++) { - //BPSK modulation - if ((encoderOutput>>i) & 1 ) { - modulatedInput[i]=-1; - } else { - modulatedInput[i]=1; - } - - //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); + 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; + + 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 'f': + SNRstop = atof(optarg); + break; + + case 'l': + messageLength = atoi(optarg); + break; + + case 'i': + iterations = atoi(optarg); + break; + + /*case 'm': + matlabDebug = 1; + //#define DEBUG_POLAR_MATLAB + 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); + + 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); + + 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 i = 0; i < NR_SMALL_BLOCK_CODED_BITS; i++) { + // BPSK modulation + if ((encoderOutput >> i) & 1) { + modulatedInput[i] = -1; + } else { + modulatedInput[i] = 1; + } + + // 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); #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 8358bd270b98371437b1a240321189c327466c7b..3078243c8f0090b0ae07ba95b183a66bbf057bfd 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<len; i++) - if ((*in & (1<<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 50559aa0d27740ddbbcd2abc53393ec22ac9e7c7..7c8554f8079e7718ed90b0eda1f1c64e4956c9f5 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 6890e525539b0642c6a4b53bdf2c9f438bca7b77..79b3daa212f7719ff25084b579c6da6c59694385 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 cccdaed8ef2ff086ef10f67eab3fe78a449c7348..1c3d0f70084894ade1a50145636bbe02ff06fcdd 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 84232ea140727d6c22dc867bfad12585ed8274bf..e878a3c0bbf2ab14993a4c6e8109f252c08e1e42 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; l<pucch_pdu->nr_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;aa<frame_parms->nb_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)); - - c16_t *r = (c16_t*)&rp[aa][l]; + memcpy(rp, &tmp_rp[re_offset[l]], nb_re_pucch * sizeof(*tmp_rp)); - for (n=0;n<nb_re_pucch;n++) { - xr[aa][l][n].r = (int32_t)x_re[l][n] * r[n].r + (int32_t)x_im[l][n] * r[n].i; - xr[aa][l][n].i = (int32_t)x_re[l][n] * r[n].i - (int32_t)x_im[l][n] * r[n].r; + for (int n = 0; n < nb_re_pucch; n++) { + xr[aa][l][n].r = (int32_t)x_re[l][n] * rp[n].r + (int32_t)x_im[l][n] * rp[n].i; + xr[aa][l][n].i = (int32_t)x_re[l][n] * rp[n].i - (int32_t)x_im[l][n] * rp[n].r; #ifdef DEBUG_NR_PUCCH_RX - printf("x (%d,%d), r%d.%d (%d,%d), xr (%lld,%lld)\n", - x_re[l][n],x_im[l][n],l2,re_offset[l],r[n].r,r[n].i,xr[aa][l][n].r,xr[aa][l][n].i); + printf("x (%d,%d), xr (%ld,%ld)\n", x_re[l][n], x_im[l][n], xr[aa][l][n].r, xr[aa][l][n].i); #endif - } - signal_energy += signal_energy_nodc((int32_t *)r, nb_re_pucch); + int energ = signal_energy_nodc((int32_t *)rp, nb_re_pucch); + signal_energy += energ; + if (aa == 0) + signal_energy_ant0 += energ; } } - signal_energy /= (pucch_pdu->nr_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;i<nr_sequences;i++){ + for (int i = 0; i < nr_sequences; i++) { c64_t corr[frame_parms->nb_antennas_rx][2]; for (int aa=0;aa<frame_parms->nb_antennas_rx;aa++) { for (int l=0;l<pucch_pdu->nr_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;aa<frame_parms->nb_antennas_rx;aa++) - temp+=squaredMod(corr[aa][0]); - } else { - temp=0; - 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; - } + 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;aa<frame_parms->nb_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;aa<frame_parms->nb_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;aa<frame_parms->nb_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;l<nrofSymbols;l++){ //extracting data and dmrs from rxdataF - if ((intraSlotFrequencyHopping == 1) && (l<floor(nrofSymbols/2))) { // intra-slot hopping enabled, we need to calculate new offset PRB + c16_t z_rx[MAX_SIZE_Z] = {0}; + c16_t z_dmrs_rx[MAX_SIZE_Z] = {0}; + const int half_nb_rb_dl = frame_parms->N_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; } - - 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; + int re_offset = (l + startingSymbolIndex) * frame_parms->ofdm_symbol_size; + + 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]; -#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]); -#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]); + 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 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]); + 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 - // 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<nrofSymbols; l++) { + for (int l = 0; l < nrofSymbols; l++) { #ifdef DEBUG_NR_PUCCH_RX printf("\t [nr_generate_pucch1] for symbol l=%d, lprime=%d\n", l,lprime); #endif // y_n contains the complex value d multiplied by the sequence r_u_v - if ((intraSlotFrequencyHopping == 1) && (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]; - } - } - else{ - if(l<round(nrofSymbols/4)){ - for(int n=0;n<12;n++){ - H_re[n]=round(z_dmrs_re_rx[l*12+n]/round(nrofSymbols/4))+H_re[n]; - H_im[n]=round(z_dmrs_im_rx[l*12+n]/round(nrofSymbols/4))+H_im[n]; - } - } - else{ - for(int n=0;n<12;n++){ - H1_re[n]=round(z_dmrs_re_rx[l*12+n]/(ceil(nrofSymbols/2)-round(nrofSymbols/4)))+H1_re[n]; - H1_im[n]=round(z_dmrs_im_rx[l*12+n]/(ceil(nrofSymbols/2))-round(nrofSymbols/4))+H1_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; } - } - } - //averaging information sequences - for(l=0;l<floor(nrofSymbols/2);l++){ - if(intraSlotFrequencyHopping==0){ - for(int n=0;n<12;n++){ - y_n_re[n]=round(z_re_rx[l*12+n]/floor(nrofSymbols/2))+y_n_re[n]; - y_n_im[n]=round(z_im_rx[l*12+n]/floor(nrofSymbols/2))+y_n_im[n]; - } - } - else{ - if(l<floor(nrofSymbols/4)){ - for(int n=0;n<12;n++){ - y_n_re[n]=round(z_re_rx[l*12+n]/floor(nrofSymbols/4))+y_n_re[n]; - y_n_im[n]=round(z_im_rx[l*12+n]/floor(nrofSymbols/4))+y_n_im[n]; - } - } - else{ - for(int n=0;n<12;n++){ - y1_n_re[n]=round(z_re_rx[l*12+n]/round(nrofSymbols/4))+y1_n_re[n]; - y1_n_im[n]=round(z_im_rx[l*12+n]/round(nrofSymbols/4))+y1_n_im[n]; + } else { + if (l < nrofSymbols / 4) { + for (int n = 0; n < 12; n++) { + H[n].r += z_dmrs_rx[l * 12 + n].r / quarter_nb_symbols; + H[n].i += z_dmrs_rx[l * 12 + n].i / quarter_nb_symbols; + y_n[n].r += z_rx[l * 12 + n].r / quarter_nb_symbols; + y_n[n].i += z_rx[l * 12 + n].i / quarter_nb_symbols; } - } + } else { + for (int n = 0; n < 12; n++) { + H1[n].r += z_dmrs_rx[l * 12 + n].r / quarter_nb_symbols; + H1[n].i += z_dmrs_rx[l * 12 + n].i / quarter_nb_symbols; + y1_n[n].r += z_rx[l * 12 + n].r / quarter_nb_symbols; + y1_n[n].i += z_rx[l * 12 + n].i / quarter_nb_symbols; + } + } } } // mrc combining to obtain z_re and z_im - if(intraSlotFrequencyHopping==0){ - 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; + 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; - } - 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; + if (nr_bit == 1) { + if ((d.r + d.i) > 0) { + *payload = 0; + } else { + *payload = 1; } - 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_lut[9]={pucch2_3bit, - pucch2_4bit, - pucch2_5bit, - pucch2_6bit, - pucch2_7bit, - pucch2_8bit, - pucch2_9bit, - pucch2_10bit, - pucch2_11bit}; +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}; 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<<b);i++) { - out=encodeSmallBlock(&i,b); + for (int i = 0; i < (1 << b); i++) { + out = encodeSmallBlock(i, b); #ifdef DEBUG_NR_PUCCH_RX if (b==3) printf("in %d, out %x\n",i,out); #endif @@ -1066,7 +937,7 @@ void init_pucch2_luts() { *lut_ip1 = simde_mm256_insert_epi16(*lut_ip1,bit,15); } } - for (uint16_t i=0;i<16;i++) { + for (int i = 0; i < 16; i++) { simde__m64 *lut_i=&pucch2_polar_4bit[i]; bit = (i&0x1) > 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; symb<pucch_pdu->nr_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; symb<pucch_pdu->nr_of_symbols;symb++) { // 24 REs contains 48x16-bit, so 6x8x16-bit - for (int aa=0;aa<Prx;aa++) { + for (int aa = 0; aa < Prx; aa++) { for (int prb = 0; prb < pucch_pdu->prb_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<ngroup;group++) { + for (int group = 0; group < ngroup; group++) { // each group has 8*nc_group_size elements, compute 1 complex correlation with DMRS per group // non-coherent combining across groups simde__m64 dmrs_re = byte2m64_re[sGold8[(group & 1) << 1]]; @@ -1280,9 +1158,8 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, simde__m64 dmrs_im = byte2m64_im[sGold8[(group & 1) << 1]]; int16_t *dmrs_im16 = (int16_t *)&dmrs_im; #ifdef DEBUG_NR_PUCCH_RX - printf("Group %d: s %x x2 %x ((%d,%d),(%d,%d),(%d,%d),(%d,%d))\n", + printf("Group %d: x2 %x ((%d,%d),(%d,%d),(%d,%d),(%d,%d))\n", group, - ((uint16_t *)&s)[0], x2, dmrs_re16[0], dmrs_im16[0], @@ -1308,7 +1185,7 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, for (int z = 0; z < 4; z++) { corr32_re[symb][group][aa] += rd_re_ext_p[z] * dmrs_re16[z] + rd_im_ext_p[z] * dmrs_im16[z]; corr32_im[symb][group][aa] += -rd_re_ext_p[z] * dmrs_im16[z] + rd_im_ext_p[z] * dmrs_re16[z]; - } + } } dmrs_re = byte2m64_re[sGold8[1 + ((group & 1) << 1)]]; dmrs_im = byte2m64_im[sGold8[1 + ((group & 1) << 1)]]; @@ -1340,7 +1217,7 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, corr32_re[symb][group][aa] += rd_re_ext_p[z + 4] * dmrs_re16[z] + rd_im_ext_p[z + 4] * dmrs_im16[z]; corr32_im[symb][group][aa] += -rd_re_ext_p[z + 4] * dmrs_im16[z] + rd_im_ext_p[z + 4] * dmrs_re16[z]; } - /* corr32_re[group][aa]>>=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;symb<pucch_pdu->nr_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<ngroup;group++) { // do complex correlation for (int aa=0;aa<Prx;aa++) { - prod_re[aa] = /*simde_mm256_srai_epi16(*/simde_mm256_adds_epi16(simde_mm256_mullo_epi16(pucch2_lut[nb_bit-3][cw<<1],rp_re[aa][symb][group]), - simde_mm256_mullo_epi16(pucch2_lut[nb_bit-3][(cw<<1)+1],rp_im[aa][symb][group]))/*,5)*/; - prod_im[aa] = /*simde_mm256_srai_epi16(*/simde_mm256_subs_epi16(simde_mm256_mullo_epi16(pucch2_lut[nb_bit-3][cw<<1],rp2_im[aa][symb][group]), - simde_mm256_mullo_epi16(pucch2_lut[nb_bit-3][(cw<<1)+1],rp2_re[aa][symb][group]))/*,5)*/; + prod_re[aa] = /*simde_mm256_srai_epi16(*/ simde_mm256_adds_epi16( + simde_mm256_mullo_epi16(pucch2_lut[nb_bit - 3][cw << 1], rp_re[aa][symb][group]), + simde_mm256_mullo_epi16(pucch2_lut[nb_bit - 3][(cw << 1) + 1], rp_im[aa][symb][group])) /*,5)*/; + prod_im[aa] = /*simde_mm256_srai_epi16(*/ simde_mm256_subs_epi16( + simde_mm256_mullo_epi16(pucch2_lut[nb_bit - 3][cw << 1], rp2_im[aa][symb][group]), + simde_mm256_mullo_epi16(pucch2_lut[nb_bit - 3][(cw << 1) + 1], rp2_re[aa][symb][group])) /*,5)*/; #ifdef DEBUG_NR_PUCCH_RX printf("prod_re[%d] => (%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<Prx;aa++) { - 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_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)); - - 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); - - 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 + ((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); + + 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, + "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 (;i<harq_bytes-1;i++) { uci_pdu->harq.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<<bit_left)-1); - 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] >>= 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 b73d432f2ebe5b6be65d84463289f0a9d9062c77..19f7e89a7fb70eb6fb3ec61aad0fff5c87436de4 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; l<pucch_pdu->nr_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; l<pucch_pdu->nr_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; rb<pucch_pdu->prb_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<m_symbol; i++) { // PI/2-BPSK modulation subclause 5.1.1 - if (((btilde[i]&1)==0) && (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)==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<floor((n_SF_PUCCH_s*m_symbol)/(12*nrofPRB)); l++) { for (int k=0; k<(12*nrofPRB); k++) { - z_re[l*(12*nrofPRB)+k] = 0; - z_im[l*(12*nrofPRB)+k] = 0; - - // int16_t z_re_tmp[240] = {0}; - // int16_t z_im_tmp[240] = {0}; - for (int m=0; m<(12*nrofPRB); m++) { - //z_re[l*(12*nrofPRB)+k] = y_n_re[l*(12*nrofPRB)+m] * (int16_t)(round(32767*cos((2*M_PI*m*k)/(12*nrofPRB)))); - // z_re_tmp[m] = (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_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<nrofSymbols; l++) { - if ((intraSlotFrequencyHopping == 1) && (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; rb<nrofPRB; rb++) { + 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; if ((intraSlotFrequencyHopping == 1) && (l<floor(nrofSymbols/2))) { // intra-slot hopping enabled, we need to calculate new offset PRB startingPRB = startingPRB + pucch_pdu->second_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 e98b20b277f3408a832315d752c5c838fbc68f79..cd99eb497ea58f9ebd52e21623b82b21ca623dbf 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 3f99a22b71b89b3d3c3d47a91eb653a045c38706..fddb48472756a8924fe9e552056c95a3c5e32a28 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 49739399765c82e2114857b6e028117dfd6ebb0d..180b580916875087e6f2c5dddcfc52b2c996a91a 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 f43d7a8dc591e90fe607923c94d5ec0b7f1ab30d..355b8b3e90840b44ecfe02a668bbb5b08132ff63 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 8fc3a8514abcce7af33bca7b49bae5cfbab5bff8..ccc2d9f03081fbe976576bf689052c43b1710c32 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 018cfcb4068f37600d2422feddc8197827743589..1080ee7faaa5b1392cd911b16031c298aca65750 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 146e7a6f4f7d283a4253f52da3247ca74093414a..7e7da9c4f84c765234a2a85a4a5c3c15f7b7a61d 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 d92e0c4fa7bf561ff8e4bc5dde4e8c7a9fd78fb0..4c010304b73fe4ffbffd3d42cbc06995a31397ab 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 0131551ed299402e5d7c5db45193752eacf70954..6ae2df12ebf1055927b2c5351ddf205b19ef348c 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 075afc2bd9df8588d65258e838f2503f78e4ee42..1bd991f7c5d685986045772b5af91e423700bdeb 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 91cc805d22d8da8e6205f42d05dfd010be783294..9118fce36afd2fcd49f06a75069281d41387a157 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 8107f97abcc34b879fe9677b9231d770fc88b249..75e959f6cc35575694070ece144630d8ff5f6644 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 e1d63bc6d869b10000c15639bc07ecffa04e3354..425782cddc0f3dd0e3dc452830ec2043de67b5e2 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 c5b815a7e2346341b1b0b85edd0e5ad83ac46a3f..8227a78e01b09b0db7efe87677ae484e82adf998 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 18e3ce1309058efc01e2137ae906492ad1e941d9..7d525e3894b46537f180d53d62c886515c72bea9 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 2022f46a5b61501621977db2aaa4282d2c959948..d2526c6c60d1cf874b298594ed891d731d5f805b 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 a812986d1fb6e564bb08c50538976bfffed14bc0..da4a2b3f8c68bd377fd4abc534c277df66f0ccbc 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 0e9dae192fe46e07b7ed4ac739b1bb400f6f4fee..f5f4d0beb18f9b56722a7a1f4f55a91725c2e8e2 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 042d17c89904eb05320c6ad39828312e09ddc461..2f550e642a6fba3aff2f3f80be12679069529234 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 f5e060e251d0c353bc84cf0843e9f826d11261af..4a1295af9e594d314bef43163fb66461f21ed92a 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; - - 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; - - memset(&RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete->dedicatedNAS_Message,0,sizeof(OCTET_STRING_t)); - OCTET_STRING_fromBuf(&RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete->dedicatedNAS_Message,dedicatedInfoNAS,dedicatedInfoNASLength); + NR_RRCSetupComplete_IEs_t *ies = RrcSetupComplete->criticalExtensions.choice.rrcSetupComplete; + ies->selectedPLMN_Identity = sel_plmn_id; + ies->registeredAMF = NULL; + + 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(&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 98f67918d3f0517b945b16737a5d9589b1071297..5ff35d4dc60bda4e0397267f236f9c1a71baa9b8 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 4266716799e80b5c7c9486d5a2c387e930d74969..768d4caf1adbb8c54967d3abdb1cd0c68f63b1c1 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 1b4df0d7970ef684287d27856d8552a133625e37..08db8f6506e6724a4a16e784595e4bb5d86f7252 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 0a7010850d8bc9e4528dc14cf1abb9f6234d99dc..5b4823d03dc4546d9379e25ac5a5803c54275c24 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 c34d777bd5677c9226685e0c209cd8e6bbd666a2..d7c5c5d7197dab5f4dd779e965bc177f49768a09 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 e0d3ade23a288d8dc18a9343a6415e5a8aaeacc9..30c434c662883c73e669c240aaa18cffb5614374 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 ea877481e6ade98a78473347c50417c44ccf81d2..c0b60f101f2bc95f11f9cd8138fc489754345930 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 82d943fd194fde908d691181fd5456f0bab88435..9356a46eff09e22a27042abe1a65d7656f203ea9 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 4b7c4cc45c111ae8fdb56d4291cd0e5e534e024d..d73e95b030a10e4818f67ea0ce7112750b0dbc75 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 1974e55f505a195dc2a743394bad07b31ea73cc1..4b338608098d43f0a8efdf0e25ee49d7dabbfc90 100644 --- a/radio/rfsimulator/README.md +++ b/radio/rfsimulator/README.md @@ -1,65 +1,66 @@ -# 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). +[[_TOC_]] -It can be run either in: +# General -- "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 +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. +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). -# 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 <path to oai sources>/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 <config file> --rfsim --rfsimulator.serveraddr server +``` +Often, configuration files define the corresponding `rfsimulator` section, in +which case you might omit `--rfsimulator.serveraddr server`. Example: +``` +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. + +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-softmodem -O <config file> --rfsim +sudo ./lte-uesoftmodem -C 2685000000 -r 50 --rfsim --rfsimulator.serveraddr 192.168.2.200 ``` +For running on the same host, only `--rfsim` is necessary. -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. +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: -```bash -cd ran_build/build -make rfsimulator -``` - -### Launch gNB in one window +Similarly as for 4G, first launch the gNB, here in an example for the phytest: ```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 +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 UE in another 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-uesoftmodem --rfsim --phy-test --rfsimulator.serveraddr <TARGET_GNB_INTERFACE_ADDRESS> +sudo ./nr-uesoftmodem --rfsim --phy-test --rfsimulator.serveraddr <TARGET_GNB_IP_ADDRESS> ``` 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. <TARGET_GNB_INTERFACE_ADDRESS> 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. `<TARGET_GNB_IP_ADDRESS>` 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 <channelid> <param> <value> channelmod modify 0 ploss 15 ``` -where: -```bash -<param name> can be one of "riceanf", "aoa", "randaoa", "ploss", "offset", "forgetf" -``` +where `<param>` 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.