diff --git a/nfapi/open-nFAPI/common/src/nfapi.c b/nfapi/open-nFAPI/common/src/nfapi.c index e9aa3c96822d3318d8fb2967092bbc1837618246..ae3ab85c05bf87065b5f165f3168f28ea1ef8164 100644 --- a/nfapi/open-nFAPI/common/src/nfapi.c +++ b/nfapi/open-nFAPI/common/src/nfapi.c @@ -620,39 +620,59 @@ uint8_t unpackarray(uint8_t **ppReadPackedMsg, uint32_t pack_dci_payload(uint8_t payload[], uint16_t payloadSizeBits, uint8_t **out, uint8_t *end) { - // Helper vars for DCI Payload - uint8_t dci_bytes_inverted[DCI_PAYLOAD_BYTE_LEN]; uint8_t dci_byte_len = (payloadSizeBits + 7) / 8; +#ifdef FAPI_BYTE_ORDERING_BIG_ENDIAN + // Helper vars for DCI Payload + uint8_t dci_bytes_inverted[DCI_PAYLOAD_BYTE_LEN] = {0}; + uint8_t payload_internal[DCI_PAYLOAD_BYTE_LEN] = {0}; // Used to not edit the "outside" pointer + uint8_t rotation_bits = 0; // Align the dci payload bits to the left on the payload buffer - uint64_t *dci_pdu = (uint64_t *)payload; if (payloadSizeBits % 8 != 0) { - uint8_t rotation_bits = 8 - (payloadSizeBits % 8); - *dci_pdu = (*dci_pdu << rotation_bits); + rotation_bits = 8 - (payloadSizeBits % 8); + // Bit shifting value ( << ) + uint64_t t = 0; + memcpy(&t, payload, dci_byte_len); + t = t << rotation_bits; + memcpy(payload_internal, &t, dci_byte_len); + } else { + // No rotation needed + memcpy(payload_internal, payload, dci_byte_len); } // Invert the byte order of the DCI Payload for (int j = 0; j < dci_byte_len; j++) { - dci_bytes_inverted[j] = payload[(dci_byte_len - 1) - j]; + dci_bytes_inverted[j] = payload_internal[(dci_byte_len - 1) - j]; } return pusharray8(dci_bytes_inverted, DCI_PAYLOAD_BYTE_LEN, dci_byte_len, out, end); +#else + return pusharray8(payload, DCI_PAYLOAD_BYTE_LEN, dci_byte_len, out, end); +#endif } uint32_t unpack_dci_payload(uint8_t payload[], uint16_t payloadSizeBits, uint8_t **in, uint8_t *end) { // Pull the inverted DCI and invert it back // Helper vars for DCI Payload - uint8_t dci_bytes_inverted[DCI_PAYLOAD_BYTE_LEN]; uint8_t dci_byte_len = (payloadSizeBits + 7) / 8; +#ifdef FAPI_BYTE_ORDERING_BIG_ENDIAN + uint8_t dci_bytes_inverted[DCI_PAYLOAD_BYTE_LEN] = {0}; // Get DCI array inverted uint32_t pullresult = pullarray8(in, dci_bytes_inverted, DCI_PAYLOAD_BYTE_LEN, dci_byte_len, end); - uint64_t *dci_pdu = (uint64_t *)payload; + // Reversing the byte order of the inverted DCI payload for (uint16_t j = 0; j < dci_byte_len; j++) { payload[j] = dci_bytes_inverted[(dci_byte_len - 1) - j]; } + + uint64_t t = 0; + memcpy(&t, payload, dci_byte_len); if (payloadSizeBits % 8 != 0) { uint8_t rotation_bits = 8 - (payloadSizeBits % 8); - *dci_pdu = (*dci_pdu >> rotation_bits); + t = (t >> (uint64_t)rotation_bits); } + memcpy(payload, &t, dci_byte_len); +#else + uint32_t pullresult = pullarray8(in, payload, DCI_PAYLOAD_BYTE_LEN, dci_byte_len, end); +#endif return pullresult; } diff --git a/nfapi/tests/CMakeLists.txt b/nfapi/tests/CMakeLists.txt index f04f7fe7a2174a498d7c20f6f313c6a506ac5856..4af1e68aa14be202d4f8d04b02352107c81c7159 100644 --- a/nfapi/tests/CMakeLists.txt +++ b/nfapi/tests/CMakeLists.txt @@ -1,3 +1,4 @@ if (ENABLE_TESTS) add_subdirectory(p5) + add_subdirectory(p7) endif () diff --git a/nfapi/tests/p7/CMakeLists.txt b/nfapi/tests/p7/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7cf1958693a8ad0b9faa480e34eb22a46f653e24 --- /dev/null +++ b/nfapi/tests/p7/CMakeLists.txt @@ -0,0 +1,16 @@ +set(Test_Labels fapi p7) +set(_fapi_p7_messages "dci_inversion") +foreach (fapi_p7_message IN LISTS _fapi_p7_messages) + add_executable(nr_fapi_${fapi_p7_message}_test nr_fapi_${fapi_p7_message}_test.c) + target_link_libraries(nr_fapi_${fapi_p7_message}_test PUBLIC nr_fapi_p5) + target_link_libraries(nr_fapi_${fapi_p7_message}_test PRIVATE pthread UTIL ${T_LIB} minimal_lib) + add_dependencies(tests nr_fapi_${fapi_p7_message}_test) + + add_test(nr_fapi_${fapi_p7_message}_test nr_fapi_${fapi_p7_message}_test) + set_tests_properties(nr_fapi_${fapi_p7_message}_test PROPERTIES LABELS "${Test_Labels}") +endforeach () +# Add the dci label for the dci payload test +set(dci_labels dci ${Test_Labels}) +set_tests_properties(nr_fapi_dci_inversion_test PROPERTIES LABELS "dci ${Test_Labels}") +# Add the FAPI_BYTE_ORDERING_BIG_ENDIAN preprocessor define in order to test the invert/uninvert dci payload functions +target_compile_definitions(nfapi_common PRIVATE FAPI_BYTE_ORDERING_BIG_ENDIAN) diff --git a/nfapi/tests/p7/nr_fapi_dci_inversion_test.c b/nfapi/tests/p7/nr_fapi_dci_inversion_test.c new file mode 100644 index 0000000000000000000000000000000000000000..4c3c05c2e3d1db130bde0a6290c38b944d721837 --- /dev/null +++ b/nfapi/tests/p7/nr_fapi_dci_inversion_test.c @@ -0,0 +1,146 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ +/*! \file nfapi/tests/p5/nr_fapi_param_request_test.c + * \brief + * \author Ruben S. Silva + * \date 2024 + * \version 0.1 + * \company OpenAirInterface Software Alliance + * \email: contact@openairinterface.org, rsilva@allbesmart.pt + * \note + * \warning + */ +#include "nfapi/tests/nr_fapi_test.h" +#include "nr_fapi_p5.h" +#include "nr_fapi.h" +void printbits(uint64_t n, uint8_t numBytesToPrint) +{ + uint64_t i; + uint8_t counter = 0; + if (numBytesToPrint == 0) { + i = 1UL << (sizeof(n) * 8 - 1); + } else { + i = 1UL << (numBytesToPrint * 8 - 1); + } + while (i > 0) { + if (n & i) + printf("1"); + else + printf("0"); + i >>= 1; + counter++; + if (counter % 8 == 0) { + printf(" "); + } + } +} + +/*! \brief Drops unwanted bits from a byte array, leaving only a specified number of payload bits + * + * \param payloadSizeBits How many bits the payload is to have, from 1 to 64 (8 * DCI_PAYLOAD_BYTE_LEN) + * \param payload[] A uint8_t array containing the payload bytes with random data + * \details This function creates a bitmask of payloadSizeBits width to truncate the data in payload[] to only have the specified + * number of payload bits\n + * For example, a payload of 39 bits needs 5 bytes, but on the last byte, the last bit is unused, this function makes sure that + * last bit is set to 0, allowing the payload to be then packed and unpacked and successfully compared with the original payload + */ +void truncate_unwanted_bits(uint8_t payloadSizeBits, uint8_t payload[]) +{ + uint8_t payloadSizeBytes = (payloadSizeBits + 7) / 8; + printf("Original Value:\t"); + uint64_t t = 0; + memcpy(&t, payload, payloadSizeBytes); + printbits(t, payloadSizeBytes); + printf("\n"); + uint64_t bitmask = 1; + for (int i = 0; i < payloadSizeBits - 1; i++) { + bitmask = bitmask << 1 | 1; + } + printf("Calculated Bitmask:\t"); + printbits(bitmask, payloadSizeBytes); + printf("\n"); + t = t & bitmask; + printf("Truncated Value:\t"); + printbits(t, payloadSizeBytes); + printf("\n"); + memcpy(payload, &t, payloadSizeBytes); +} + +/*! \brief Generates a random payload payloadSizeBits long into payload[] + * + * \param payloadSizeBits How many bits the payload is to have, from 1 to 64 (8 * DCI_PAYLOAD_BYTE_LEN) + * \param payload[] A uint8_t array to contain the generated payload + * \details This function fills a uint8_t array with payloadSizeBits of random data, by first filling however many bytes are needed + * to contain payloadSizeBits with random data, and then truncating the excess bits + */ +void generate_payload(uint8_t payloadSizeBits, uint8_t payload[]) +{ + for (int i = 0; i < (payloadSizeBits + 7) / 8; ++i) { + payload[i] = rand8(); + } + truncate_unwanted_bits(payloadSizeBits, payload); +} + +void test_pack_payload(uint8_t payloadSizeBits, uint8_t payload[]) +{ + uint8_t msg_buf[8192] = {0}; + uint8_t payloadSizeBytes = (payloadSizeBits + 7) / 8; + uint8_t *pWritePackedMessage = msg_buf; + uint8_t *pPackMessageEnd = msg_buf + sizeof(msg_buf); + + pack_dci_payload(payload, payloadSizeBits, &pWritePackedMessage, pPackMessageEnd); + + uint8_t *unpack_buf = calloc_or_fail(payloadSizeBytes, sizeof(uint8_t)); + pWritePackedMessage = msg_buf; + unpack_dci_payload(unpack_buf, payloadSizeBits, &pWritePackedMessage, pPackMessageEnd); + + printf("\nOriginal:\t"); + for (int j = payloadSizeBytes - 1; j >= 0; j--) { + printbits(payload[j], 1); + printf(" "); + } + printf("\n"); + + printf("Unpacked:\t"); + for (int j = payloadSizeBytes - 1; j >= 0; j--) { + printbits(unpack_buf[j], 1); + printf(" "); + } + printf("\n"); + + DevAssert(memcmp(payload, unpack_buf, payloadSizeBytes) == 0); + // All tests successful! + free(unpack_buf); +} + +int main(int n, char *v[]) +{ + fapi_test_init(); + uint8_t upper = 8 * DCI_PAYLOAD_BYTE_LEN; + uint8_t lower = 1; + uint8_t payloadSizeBits = (rand() % (upper - lower + 1)) + lower; // from 1 bit to DCI_PAYLOAD_BYTE_LEN, in bits + printf("payloadSizeBits:%d\n", payloadSizeBits); + uint8_t payload[(payloadSizeBits + 7) / 8]; + + generate_payload(payloadSizeBits, payload); + test_pack_payload(payloadSizeBits, payload); + return 0; +}