Add fsn lib to simplify frame/slot handling
Refactor existing code, and harmonize interface. Add a couple of tests. Signed-off-by: Robert Schmidt <robert.schmidt@openairinterface.org>
This commit is contained in:
@@ -16,7 +16,7 @@ add_subdirectory(nr)
|
||||
add_subdirectory(LOG)
|
||||
add_subdirectory(threadPool)
|
||||
add_subdirectory(time_manager)
|
||||
add_library(utils utils.c system.c time_meas.c time_stat.c tuntap_if.c reverse_bits.c)
|
||||
add_library(utils utils.c system.c time_meas.c time_stat.c tuntap_if.c reverse_bits.c fsn.c)
|
||||
target_include_directories(utils PUBLIC .)
|
||||
target_link_libraries(utils PRIVATE ${T_LIB})
|
||||
add_subdirectory(barrier)
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
#include "fsn.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
static int num_slots[5] = {10, 20, 40, 80, 160};
|
||||
|
||||
fsn_t fsn_add_delta(fsn_t fsn, uint32_t delta)
|
||||
{
|
||||
const int slots_frame = num_slots[fsn.mu];
|
||||
int next_f = fsn.f + delta / slots_frame;
|
||||
int next_s = fsn.s + delta % slots_frame;
|
||||
fsn_t res = {
|
||||
.f = (next_f + next_s / slots_frame) % 1024,
|
||||
.s = next_s % slots_frame,
|
||||
.mu = fsn.mu,
|
||||
};
|
||||
return res;
|
||||
}
|
||||
|
||||
int fsn_get_diff(fsn_t a, fsn_t b)
|
||||
{
|
||||
assert(a.mu == b.mu);
|
||||
const int slots_frame = num_slots[a.mu];
|
||||
int diff = (a.f * slots_frame + a.s) - (b.f * slots_frame + b.s);
|
||||
if (diff < -512 * slots_frame)
|
||||
diff += 1024 * slots_frame;
|
||||
else if (diff > 512 * slots_frame)
|
||||
diff -= 1024 * slots_frame;
|
||||
return diff;
|
||||
}
|
||||
|
||||
fsn_t fsn_get_max(fsn_t a, fsn_t b)
|
||||
{
|
||||
if (fsn_get_diff(a, b) <= 0) {
|
||||
return b;
|
||||
} else {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
bool fsn_equal(fsn_t a, fsn_t b)
|
||||
{
|
||||
assert(a.mu == b.mu);
|
||||
return a.f == b.f && a.s == b.s && a.mu == b.mu;
|
||||
}
|
||||
|
||||
bool fsn_in_the_past(fsn_t old, fsn_t new)
|
||||
{
|
||||
int diff = fsn_get_diff(old, new);
|
||||
return diff < 0;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
#ifndef FSN_H_
|
||||
#define FSN_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/// helper type to encapsulate a frame/slot combination in a single type.
|
||||
typedef struct fsn {
|
||||
uint16_t f; /// frame
|
||||
uint16_t s; /// slot
|
||||
uint8_t mu; /// numerology
|
||||
} fsn_t;
|
||||
|
||||
/* \brief Add delta slots to fsn. Note that this depends also on the stored
|
||||
* numerology inside fsn. */
|
||||
fsn_t fsn_add_delta(fsn_t fsn, uint32_t delta);
|
||||
|
||||
/* \brief Get difference of slots for a and b.
|
||||
* \note asserts if numerology not the same. */
|
||||
int fsn_get_diff(fsn_t a, fsn_t b);
|
||||
|
||||
/* \brief Gets the larger of two fsns */
|
||||
fsn_t fsn_get_max(fsn_t a, fsn_t b);
|
||||
|
||||
/* \brief Compare if both fsn_t's are equal */
|
||||
bool fsn_equal(fsn_t a, fsn_t b);
|
||||
|
||||
/* \brief Determine if told is in the past of tnew. The threshold is 512
|
||||
* frames. */
|
||||
bool fsn_in_the_past(fsn_t told, fsn_t tnew);
|
||||
|
||||
#endif /* FSN_H_ */
|
||||
@@ -2,3 +2,8 @@
|
||||
|
||||
add_executable(test_tpool_vs_actors test_tpool_vs_actors.c)
|
||||
target_link_libraries(test_tpool_vs_actors PRIVATE thread-pool pthread LOG minimal_lib actor)
|
||||
|
||||
add_executable(test_fsn test_fsn.cpp)
|
||||
add_dependencies(tests test_fsn)
|
||||
target_link_libraries(test_fsn PRIVATE utils GTest::gtest)
|
||||
add_test(NAME test_fsn COMMAND ./test_fsn)
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
extern "C" {
|
||||
#include "fsn.h"
|
||||
}
|
||||
|
||||
TEST(fsn, test_mu0_fsn_add) {
|
||||
fsn_t current = {123, 5, 0};
|
||||
fsn_t next = current;
|
||||
|
||||
next = fsn_add_delta(next, 12);
|
||||
EXPECT_EQ(next.f, 124);
|
||||
EXPECT_EQ(next.s, 7);
|
||||
EXPECT_EQ(next.mu, 0);
|
||||
|
||||
next = fsn_add_delta(next, 10);
|
||||
EXPECT_EQ(next.f, 125);
|
||||
EXPECT_EQ(next.s, 7);
|
||||
EXPECT_EQ(next.mu, 0);
|
||||
|
||||
next = fsn_add_delta(next, 10 * 1024);
|
||||
EXPECT_EQ(next.f, 125);
|
||||
EXPECT_EQ(next.s, 7);
|
||||
EXPECT_EQ(next.mu, 0);
|
||||
}
|
||||
|
||||
TEST(fsn, test_mu0_get_diff) {
|
||||
fsn_t current = {123, 5, 0};
|
||||
fsn_t next = fsn_add_delta(current, 12);
|
||||
int diff;
|
||||
|
||||
diff = fsn_get_diff(current, next);
|
||||
EXPECT_EQ(diff, -12);
|
||||
|
||||
diff = fsn_get_diff(next, current);
|
||||
EXPECT_EQ(diff, 12);
|
||||
}
|
||||
|
||||
TEST(fsn, test_mu0_get_max) {
|
||||
fsn_t current = {123, 5, 0};
|
||||
fsn_t next = {125, 7, 0};
|
||||
|
||||
fsn_t max = fsn_get_max(current, next);
|
||||
EXPECT_EQ(max.f, next.f);
|
||||
EXPECT_EQ(max.s, next.s);
|
||||
EXPECT_EQ(max.mu, next.mu);
|
||||
}
|
||||
|
||||
TEST(fsn, test_mu0_equal) {
|
||||
fsn_t a = {123, 5, 0};
|
||||
fsn_t b = a;
|
||||
fsn_t c = {123, 6, 0};
|
||||
|
||||
EXPECT_TRUE(fsn_equal(a, b));
|
||||
EXPECT_FALSE(fsn_equal(a, c));
|
||||
}
|
||||
|
||||
TEST(fsn, test_mu0_in_the_past) {
|
||||
fsn_t a = {0, 0, 0};
|
||||
fsn_t n = {100, 9, 0};
|
||||
fsn_t b_bef = {511, 9, 0};
|
||||
fsn_t b_ex = {512, 0, 0};
|
||||
fsn_t b_aft = {512, 1, 0};
|
||||
|
||||
// a is in the past of n
|
||||
EXPECT_TRUE(fsn_in_the_past(a, n));
|
||||
// similarly, a is in the past of b_bef
|
||||
EXPECT_TRUE(fsn_in_the_past(a, b_bef));
|
||||
// difference "to both sides" is 512 frames, so we consider a still in the
|
||||
// past of b_ex
|
||||
EXPECT_TRUE(fsn_in_the_past(a, b_ex));
|
||||
// (b_aft - a) < (a - b_aft) => b_aft is in the past of a because of
|
||||
// wrap-around
|
||||
EXPECT_TRUE(fsn_in_the_past(b_aft, a));
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
Reference in New Issue
Block a user