Commit 90b773a4 authored by mir's avatar mir

Decoding in RF Sim working

parent 3f3a9869
......@@ -650,6 +650,7 @@ add_library(UTIL
${OPENAIR2_DIR}/UTIL/MATH/oml.c
${OPENAIR2_DIR}/UTIL/OPT/probe.c
${OPENAIR_DIR}/common/utils/threadPool/thread-pool.c
${OPENAIR_DIR}/common/utils/thread_pool/task_manager.c
${OPENAIR_DIR}/common/utils/utils.c
${OPENAIR_DIR}/common/utils/system.c
${OPENAIR_DIR}/common/utils/time_meas.c
......@@ -2054,6 +2055,7 @@ add_executable(nr-softmodem
${rrc_h}
${nr_rrc_h}
${s1ap_h}
# ${OPENAIR_BIN_DIR}/messages_xml.h
${OPENAIR_DIR}/executables/nr-gnb.c
${OPENAIR_DIR}/executables/nr-ru.c
${OPENAIR_DIR}/executables/nr-softmodem.c
......
Thread Pool implemented in C following the talk of Sean Parent "Better Code: Concurrency" from 2016
dyntickless contains the script to run if low-latency is needed
Remember that isolcpus, rcu_nocbs-4-7, nohz_full=4-7 and rcu_nocb_poll is needed.
The Kernel needs to be compiled appropiattely
#!/bin/bash
# Full dyntick CPU on which we'll run the user loop,
# it must be part of nohz_full kernel parameter
TARGET=4
# Migrate all possible tasks to CPU 0
for P in $(ls /proc)
do
if [ -x "/proc/$P/task/" ]
then
echo $P
taskset -acp 0 $P
fi
done
# Migrate irqs to CPU 0
for D in $(ls /proc/irq)
do
if [[ -x "/proc/irq/$D" && $D != "0" ]]
then
echo $D
echo 1 > /proc/irq/$D/smp_affinity
fi
done
# Delay the annoying vmstat timer far away
sysctl vm.stat_interval=120
# Shutdown nmi watchdog as it uses perf events
sysctl -w kernel.watchdog=0
# Remove -rt task runtime limit
echo -1 > /proc/sys/kernel/sched_rt_runtime_us
# Pin the writeback workqueue to CPU0
echo 1 > /sys/bus/workqueue/devices/writeback/cpumask
DIR=/sys/kernel/debug/tracing
echo > $DIR/trace
echo 0 > $DIR/tracing_on
# Uncomment the below for more details on what disturbs the CPU
echo 0 > $DIR/events/irq/enable
echo 1 > $DIR/events/sched/sched_switch/enable
echo 1 > $DIR/events/workqueue/workqueue_queue_work/enable
echo 1 > $DIR/events/workqueue/workqueue_execute_start/enable
echo 1 > $DIR/events/timer/hrtimer_expire_entry/enable
echo 1 > $DIR/events/timer/tick_stop/enable
echo nop > $DIR/current_tracer
echo 1 > $DIR/tracing_on
# Run a 10 secs user loop on target
taskset -c 3-7 ./a.out
#sleep 20
#killall a.out
# Checkout the trace in trace.* file
cat /sys/kernel/debug/tracing/per_cpu/cpu4/trace > trace.4
cat /sys/kernel/debug/tracing/per_cpu/cpu5/trace > trace.5
cat /sys/kernel/debug/tracing/per_cpu/cpu6/trace > trace.6
cat /sys/kernel/debug/tracing/per_cpu/cpu7/trace > trace.7
#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "task_manager.h"
#define NUM_THREADS 4
#define NUM_JOBS 1024*1024
int64_t time_now_us(void)
{
struct timespec tms;
/* The C11 way */
/* if (! timespec_get(&tms, TIME_UTC)) */
/* POSIX.1-2008 way */
if (clock_gettime(CLOCK_MONOTONIC_RAW,&tms)) {
return -1;
}
/* seconds, multiplied with 1 million */
int64_t micros = tms.tv_sec * 1000000;
/* Add full microseconds */
int64_t const tv_nsec = tms.tv_nsec;
micros += tv_nsec/1000;
/* round up if necessary */
if (tv_nsec % 1000 >= 500) {
++micros;
}
return micros;
}
typedef struct{
int64_t a;
int64_t time;
task_ans_t* ans;
} pair_t;
static inline
int64_t naive_fibonnacci(int64_t a)
{
assert(a < 1000);
if(a < 2)
return a;
return naive_fibonnacci(a-1) + naive_fibonnacci(a-2);
}
//static _Thread_local int64_t counter = 0;
static
int marker_fd;
void do_work(void* arg)
{
//int64_t now = time_now_us();
pair_t* a = (pair_t*)arg;
naive_fibonnacci(23 + a->a);
completed_task_ans(a->ans);
//int64_t stop = time_now_us();
//char buffer[100] = {0};
//int ret = snprintf(buffer, 100, "ID %lu Fib elapsed %ld start-stop %ld - %ld \n", pthread_self(), stop - now, now, stop);
//assert(ret > 0 && ret < 100);
// write_marker_ft_mir(marker_fd, buffer);
// puts(buffer);
}
int main()
{
task_manager_t man = {0};
init_task_manager(&man, NUM_THREADS);
usleep(100);
pair_t* arr = calloc(NUM_JOBS, sizeof(pair_t));
assert(arr != NULL);
task_ans_t* ans = calloc(NUM_JOBS, sizeof(task_ans_t));
assert(ans != NULL);
int64_t now = time_now_us();
for(int i = 0; i < NUM_JOBS; ++i){
pair_t* pa = &arr[i];
pa->a = 0; //i%10;
pa->time = 0;
pa->ans = &ans[i];
task_t t = {.args = pa, t.func = do_work};
async_task_manager(&man, t);
}
printf("Waiting %ld \n", time_now_us());
join_task_ans(ans, NUM_JOBS);
printf("Done %ld \n", time_now_us());
free_task_manager(&man, NULL);
printf("Total elapsed %ld \n", time_now_us() - now);
free(arr);
return EXIT_SUCCESS;
}
#ifndef TASK_WORK_STEALING_THREAD_POOL_H
#define TASK_WORK_STEALING_THREAD_POOL_H
typedef struct{
void* args;
void (*func)(void* args);
} task_t;
#endif
#define _GNU_SOURCE
#include <unistd.h>
#include "task_manager.h"
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/sysinfo.h>
#include <fcntl.h>
#include <linux/futex.h> /* Definition of FUTEX_* constants */
#include <sys/syscall.h> /* Definition of SYS_* constants */
#include <unistd.h>
#include <ctype.h> // toupper
#if defined (__i386__) || defined(__x86_64__)
#define pause_or_yield __builtin_ia32_pause
#elif __aarch64__
#define pause_or_yield() asm volatile("yield" ::: "memory")
#else
static_assert(0!=0, "Unknown CPU architecture");
#endif
/*
static
int64_t time_now_us(void)
{
struct timespec tms;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &tms)) {
return -1;
}
int64_t micros = tms.tv_sec * 1000000;
int64_t const tv_nsec = tms.tv_nsec;
micros += tv_nsec/1000;
if (tv_nsec % 1000 >= 500) {
++micros;
}
return micros;
}
static
void pin_thread_to_core(int core_num)
{
cpu_set_t set = {0};
CPU_ZERO(&set);
CPU_SET(core_num, &set);
int ret = sched_setaffinity(gettid(), sizeof(set), &set);
assert(ret != -1);
printf("Pining into core %d id %ld \n", core_num, pthread_self());
}
*/
//////////////////////////////
//////////////////////////////
////////// RING //
//////////////////////////////
//////////////////////////////
//////////////////////////////
// For working correctly, maintain the default elements to a 2^N e.g., 2^5=32
#define DEFAULT_ELM 32
typedef struct seq_ring_buf_s
{
// const size_t elt_size;
task_t* array;
size_t cap;
uint32_t head;
uint32_t tail;
_Atomic uint64_t sz;
} seq_ring_task_t;
typedef void (*seq_free_func)(task_t*);
static
size_t size_seq_ring_task(seq_ring_task_t* r)
{
assert(r != NULL);
return r->head - r->tail;
}
inline static
uint32_t mask(uint32_t cap, uint32_t val)
{
return val & (cap-1);
}
static
bool full(seq_ring_task_t* r)
{
return size_seq_ring_task(r) == r->cap -1;
}
static
void enlarge_buffer(seq_ring_task_t* r)
{
assert(r != NULL);
assert(full(r));
const uint32_t factor = 2;
task_t* tmp_buffer = calloc(r->cap * factor, sizeof(task_t) );
assert(tmp_buffer != NULL);
const uint32_t head_pos = mask(r->cap, r->head);
const uint32_t tail_pos = mask(r->cap, r->tail);
if(head_pos > tail_pos){
memcpy(tmp_buffer, r->array + tail_pos , (head_pos-tail_pos)*sizeof(task_t) );
} else {
memcpy(tmp_buffer, r->array + tail_pos, (r->cap-tail_pos)*sizeof(task_t));
memcpy(tmp_buffer + (r->cap-tail_pos), r->array, head_pos*sizeof(task_t));
}
r->cap *= factor;
free(r->array);
r->array = tmp_buffer;
r->tail = 0;
r->head = r->cap/2 - 1;
}
static
void init_seq_ring_task(seq_ring_task_t* r)
{
assert(r != NULL);
task_t* tmp_buffer = calloc(DEFAULT_ELM, sizeof(task_t));
assert(tmp_buffer != NULL);
seq_ring_task_t tmp = {.array = tmp_buffer, .head = 0, .tail = 0, .cap = DEFAULT_ELM};
memcpy(r, &tmp, sizeof(seq_ring_task_t));
r->sz = 0;
}
static
void free_seq_ring_task(seq_ring_task_t* r, seq_free_func fp)
{
assert(r != NULL);
assert(fp == NULL);
free(r->array);
}
static
void push_back_seq_ring_task(seq_ring_task_t* r, task_t t)
{
assert(r != NULL);
if(full(r))
enlarge_buffer(r);
const uint32_t pos = mask(r->cap, r->head);
r->array[pos] = t;
r->head += 1;
r->sz += 1;
}
static
task_t pop_seq_ring_task(seq_ring_task_t* r )
{
assert(r != NULL);
assert(size_seq_ring_task(r) > 0);
const uint32_t pos = mask(r->cap, r->tail);
task_t t = r->array[pos];
r->tail += 1;
r->sz -= 1;
return t;
}
#undef DEFAULT_ELM
//////////////////////////////
//////////////////////////////
////////// END RING //
//////////////////////////////
//////////////////////////////
//////////////////////////////
//////////////////////////////
//////////////////////////////
////////// Start Notification Queue //
//////////////////////////////
//////////////////////////////
//////////////////////////////
typedef struct {
pthread_mutex_t mtx;
pthread_cond_t cv;
seq_ring_task_t r;
// _Atomic int32_t* futex;
//_Atomic bool* waiting;
_Atomic int done;
} not_q_t;
typedef struct{
task_t t;
bool success;
} ret_try_t;
static
void init_not_q(not_q_t* q /*, _Atomic int32_t* futex , _Atomic bool* waiting */)
{
assert(q != NULL);
q->done = 0;
//q->waiting = waiting;
init_seq_ring_task(&q->r);
pthread_mutexattr_t attr = {0};
#ifdef _DEBUG
int const rc_mtx = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
assert(rc_mtx == 0);
#endif
int rc = pthread_mutex_init(&q->mtx, &attr);
assert(rc == 0 && "Error while creating the mtx");
pthread_condattr_t* c_attr = NULL;
rc = pthread_cond_init(&q->cv, c_attr);
assert(rc == 0);
//q->futex = futex;
}
static
void free_not_q(not_q_t* q, void (*clean)(task_t*) )
{
assert(q != NULL);
assert(q->done == 1);
free_seq_ring_task(&q->r, clean);
int rc = pthread_mutex_destroy(&q->mtx);
assert(rc == 0);
rc = pthread_cond_destroy(&q->cv);
assert(rc == 0);
}
static
bool try_push_not_q(not_q_t* q, task_t t)
{
assert(q != NULL);
assert(q->done == 0 || q->done ==1);
assert(t.func != NULL);
assert(t.args != NULL);
if(pthread_mutex_trylock(&q->mtx ) != 0)
return false;
push_back_seq_ring_task(&q->r, t);
pthread_cond_signal(&q->cv);
int const rc = pthread_mutex_unlock(&q->mtx);
assert(rc == 0);
return true;
}
static
void push_not_q(not_q_t* q, task_t t)
{
assert(q != NULL);
assert(q->done == 0 || q->done ==1);
assert(t.func != NULL);
int const rc = pthread_mutex_lock(&q->mtx);
assert(rc == 0);
push_back_seq_ring_task(&q->r, t);
pthread_cond_signal(&q->cv);
pthread_mutex_unlock(&q->mtx);
}
static
ret_try_t try_pop_not_q(not_q_t* q)
{
assert(q != NULL);
ret_try_t ret = {.success = false};
int rc = pthread_mutex_trylock(&q->mtx);
assert(rc == 0 || rc == EBUSY);
if(rc == EBUSY)
return ret;
assert(q->done == 0 || q->done ==1);
size_t sz = size_seq_ring_task(&q->r);
if(sz == 0){
rc = pthread_mutex_unlock(&q->mtx);
assert(rc == 0);
return ret;
}
assert(sz > 0);
ret.t = pop_seq_ring_task(&q->r);
rc = pthread_mutex_unlock(&q->mtx);
assert(rc == 0);
ret.success = true;
return ret;
}
static
bool pop_not_q(not_q_t* q, ret_try_t* out)
{
assert(q != NULL);
assert(out != NULL);
assert(q->done == 0 || q->done ==1);
int rc = pthread_mutex_lock(&q->mtx);
assert(rc == 0);
assert(q->done == 0 || q->done ==1);
while(size_seq_ring_task(&q->r) == 0 && q->done == 0)
pthread_cond_wait(&q->cv , &q->mtx);
/*
// Let's be conservative and not use memory_order_relaxed
// while (atomic_load_explicit(q->waiting, memory_order_seq_cst) == true){ //
// Issue X86 PAUSE or ARM YIELD instruction to reduce contention between
// hyper-threads
// pause_or_yield();
// }
pthread_mutex_lock(&q->mtx);
if(size_seq_ring_task(&q->r) == 0 && q->done == 0){
int rc = pthread_mutex_unlock(&q->mtx);
assert(rc == 0);
int val = atomic_load_explicit(q->futex, memory_order_acquire);
long r = syscall(SYS_futex, q->futex, FUTEX_WAIT_PRIVATE, val, NULL, 0);
assert(r != -1);
goto label;
}
*/
//printf("Waking %ld id %ld \n", time_now_us(), pthread_self());
assert(q->done == 0 || q->done ==1);
if(q->done == 1){
//printf("Done, returning \n");
int rc = pthread_mutex_unlock(&q->mtx);
assert(rc == 0);
return false;
}
out->t = pop_seq_ring_task(&q->r);
rc = pthread_mutex_unlock(&q->mtx);
assert(rc == 0);
return true;
}
static
void done_not_q(not_q_t* q)
{
assert(q != NULL);
int rc = pthread_mutex_lock(&q->mtx);
assert(rc == 0);
q->done = 1;
rc = pthread_cond_signal(&q->cv);
assert(rc == 0);
//long r = syscall(SYS_futex, q->futex, FUTEX_WAKE_PRIVATE, INT_MAX, NULL, NULL, 0);
//assert(r != -1);
rc = pthread_mutex_unlock(&q->mtx);
assert(rc == 0);
// q->futex++;
}
//////////////////////////////
//////////////////////////////
////////// END Notification Queue //
//////////////////////////////
//////////////////////////////
//////////////////////////////
//static int marker_fd;
typedef struct{
task_manager_t* man;
int idx;
} task_thread_args_t;
// Just for debugging purposes, it is very slow!!!!
//static
//_Atomic int cnt_out = 0;
//static
//_Atomic int cnt_in = 0;
static
void* worker_thread(void* arg)
{
assert(arg != NULL);
task_thread_args_t* args = (task_thread_args_t*)arg;
int const idx = args->idx;
//int const log_cores = get_nprocs_conf();
//assert(log_cores > 0);
// Assuming: 2 x Physical cores = Logical cores
//pin_thread_to_core(idx+log_cores/2);
task_manager_t* man = args->man;
uint32_t const len = man->len_thr;
uint32_t const num_it = 2*(man->len_thr + idx);
not_q_t* q_arr = (not_q_t*)man->q_arr;
int acc_num_task = 0;
for(;;){
ret_try_t ret = {.success = false};
for(uint32_t i = idx; i < num_it; ++i){
ret = try_pop_not_q(&q_arr[i%len]);
if(ret.success == true){
break;
}
}
if(ret.success == false){
man->num_task -= acc_num_task;
acc_num_task = 0;
if(pop_not_q(&q_arr[idx], &ret) == false)
break;
}
//int64_t now = time_now_us();
//printf("Calling fuinc \n");
ret.t.func(ret.t.args);
//printf("Returning from func \n");
//int64_t stop = time_now_us();
//cnt_out++;
//printf("Tasks out %d %ld \n", cnt_out, time_now_us());
acc_num_task +=1;
}
free(args);
return NULL;
}
void init_task_manager(task_manager_t* man, size_t num_threads)
{
assert(man != NULL);
assert(num_threads > 0 && num_threads < 33 && "Do you have zero or more than 32 processors??");
printf("[MIR]: number of threads %ld \n", num_threads);
man->q_arr = calloc(num_threads, sizeof(not_q_t));
assert(man->q_arr != NULL && "Memory exhausted");
not_q_t* q_arr = (not_q_t*)man->q_arr;
for(size_t i = 0; i < num_threads; ++i){
init_not_q(&q_arr[i]);
}
man->t_arr = calloc(num_threads, sizeof(pthread_t));
assert(man->t_arr != NULL && "Memory exhausted" );
man->len_thr = num_threads;
for(size_t i = 0; i < num_threads; ++i){
task_thread_args_t* args = malloc(sizeof(task_thread_args_t) );
args->idx = i;
args->man = man;
pthread_attr_t attr = {0};
/*
int ret=pthread_attr_init(&attr);
assert(ret == 0);
ret=pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
assert(ret == 0);
ret=pthread_attr_setschedpolicy(&attr, SCHED_RR);
assert(ret == 0);
struct sched_param sparam={0};
sparam.sched_priority = 94;
ret=pthread_attr_setschedparam(&attr, &sparam);
*/
int rc = pthread_create(&man->t_arr[i], &attr, worker_thread, args);
assert(rc == 0 && "Error creating a thread");
}
man->index = 0;
//pin_thread_to_core(3);
}
void free_task_manager(task_manager_t* man, void (*clean)(task_t*))
{
not_q_t* q_arr = (not_q_t*)man->q_arr;
//atomic_store(&man->waiting, false);
for(uint32_t i = 0; i < man->len_thr; ++i){
done_not_q(&q_arr[i]);
}
for(uint32_t i = 0; i < man->len_thr; ++i){
int rc = pthread_join(man->t_arr[i], NULL);
assert(rc == 0);
}
for(uint32_t i = 0; i < man->len_thr; ++i){
free_not_q(&q_arr[i], clean);
}
free(man->q_arr);
free(man->t_arr);
}
void async_task_manager(task_manager_t* man, task_t t)
{
assert(man != NULL);
assert(man->len_thr > 0);
assert(t.func != NULL);
//assert(t.args != NULL);
uint64_t const index = man->index++;
const uint32_t len_thr = man->len_thr;
not_q_t* q_arr = (not_q_t*)man->q_arr;
for(uint32_t i = 0; i < len_thr ; ++i){
if(try_push_not_q(&q_arr[(i+index) % len_thr], t)){
man->num_task +=1;
// Debbugging purposes
//cnt_in++;
//printf("Tasks in %d %ld \n", cnt_in, time_now_us());
return;
}
}
push_not_q(&q_arr[index%len_thr], t);
man->num_task +=1;
// Debbugging purposes
//cnt_in++;
//printf("Tasks in %d %ld \n", cnt_in, time_now_us());
}
void completed_task_ans(task_ans_t* task)
{
assert(task != NULL);
int const task_not_completed = 0;
assert(atomic_load_explicit(&task->status, memory_order_acquire) == task_not_completed && "Task already finished?");
atomic_store_explicit(&task->status, 1, memory_order_release);
}
// This function does not belong here logically
//
void join_task_ans(task_ans_t* arr, size_t len)
{
assert(len > 0);
assert(arr != NULL);
// We are believing Fedor
const struct timespec ns = {0,1};
uint64_t i = 0;
int j = len -1;
for(; j != -1 ; i++){
for(; j != -1; --j){
int const task_completed = 1;
if(atomic_load_explicit(&arr[j].status, memory_order_acquire) != task_completed)
break;
}
if(i % 8 == 0){
nanosleep(&ns, NULL);
}
//sched_yield();
// pause_or_yield();
}
}
// Compatibility with previous TPool
int parse_num_threads(char const* params)
{
assert(params != NULL);
char *saveptr = NULL;
char* params_cpy = strdup(params);
char* curptr = strtok_r(params_cpy, ",", &saveptr);
int nbThreads = 0;
while (curptr != NULL) {
int const c = toupper(curptr[0]);
switch (c) {
case 'N': {
// pool->activated=false;
free(params_cpy);
return 1;
break;
}
default: {
int const core_id = atoi(curptr);
printf("[MIR]: Ask to create a thread for core %d ignoring request\n", core_id);
nbThreads++;
}
}
curptr = strtok_r(NULL, ",", &saveptr);
}
free(params_cpy);
return nbThreads;
}
#undef pause_or_yield
#ifndef TASK_MANAGER_WORKING_STEALING_H
#define TASK_MANAGER_WORKING_STEALING_H
// Comment for deactivating ws tpool
#define TASK_MANAGER_DECODING
//#define TASK_MANAGER_DEMODULATION
//#define TASK_MANAGER_CODING
//#define TASK_MANAGER_RU
//#define TASK_MANAGER_UE
//#define TASK_MANAGER_UE_DECODING
//#define TASK_MANAGER_SIM
//#define TASK_MANAGER_LTE
// LTE
//#define TASK_MANAGER_LTE
#include "task.h"
#ifndef __cplusplus
#include <stdalign.h>
#include <stdatomic.h>
#else
#include <atomic>
#define _Atomic(X) std::atomic< X >
#define _Alignas(X) alignas(X)
#endif
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#if defined (__i386__) || defined(__x86_64__)
#define LEVEL1_DCACHE_LINESIZE 64
#elif __aarch64__
// This is not always true for ARM
// in linux, you can obtain the size at runtime using sysconf (_SC_LEVEL1_DCACHE_LINESIZE)
// in c++ using std::hardware_destructive_interference_size
#define LEVEL1_DCACHE_LINESIZE 64
#else
static_assert(0!=0, "Unknown CPU architecture");
#endif
typedef struct{
// Avoid false sharing
_Alignas(LEVEL1_DCACHE_LINESIZE) _Atomic(int) status;
} task_ans_t;
void join_task_ans(task_ans_t* arr, size_t len);
void completed_task_ans(task_ans_t* task);
typedef struct{
uint8_t* buf;
size_t len;
task_ans_t* ans;
} thread_info_tm_t;
typedef struct{
pthread_t* t_arr;
size_t len_thr;
_Atomic(uint64_t) index;
void* q_arr;
_Atomic(uint64_t) num_task;
} task_manager_t;
void init_task_manager(task_manager_t* man, size_t num_threads);
void free_task_manager(task_manager_t* man, void (*clean)(task_t* args) );
void async_task_manager(task_manager_t* man, task_t t);
// Compatibility with previous TPool
int parse_num_threads(char const* params);
#endif
......@@ -90,6 +90,8 @@
#include <openair1/PHY/NR_TRANSPORT/nr_dlsch.h>
#include <PHY/NR_ESTIMATION/nr_ul_estimation.h>
#include "common/utils/thread_pool/task_manager.h"
//#define USRP_DEBUG 1
// Fix per CC openair rf/if device update
// extern openair0_device openair0;
......@@ -366,8 +368,15 @@ void *nrL1_stats_thread(void *param) {
}
void init_gNB_Tpool(int inst) {
PHY_VARS_gNB *gNB;
gNB = RC.gNB[inst];
#ifdef TASK_MANAGER_DECODING
int const num_threads = parse_num_threads(get_softmodem_params()->threadPoolConfig);
init_task_manager(&gNB->man, num_threads);
#endif
gNB_L1_proc_t *proc = &gNB->proc;
// PUSCH symbols per thread need to be calculated by how many threads we have
gNB->num_pusch_symbols_per_thread = 1;
......@@ -406,7 +415,13 @@ void init_gNB_Tpool(int inst) {
void term_gNB_Tpool(int inst) {
PHY_VARS_gNB *gNB = RC.gNB[inst];
#ifdef TASK_MANAGER_DECODING
void (*clean)(task_t*) = NULL;
free_task_manager(&gNB->man , clean);
#else
abortTpool(&gNB->threadPool);
#endif
abortNotifiedFIFO(&gNB->respDecode);
abortNotifiedFIFO(&gNB->resp_L1);
abortNotifiedFIFO(&gNB->L1_tx_free);
......
......@@ -144,6 +144,7 @@ void clean_gNB_dlsch(NR_gNB_DLSCH_t *dlsch) {
void ldpc8blocks(void *p)
{
// assert(0!=0);
encoder_implemparams_t *impp=(encoder_implemparams_t *) p;
NR_DL_gNB_HARQ_t *harq = (NR_DL_gNB_HARQ_t *)impp->harq;
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &harq->pdsch_pdu.pdsch_pdu_rel15;
......@@ -383,7 +384,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
r_offset += impp.E;
}
} else {
notifiedFIFO_t nf;
notifiedFIFO_t nf = {0};
initNotifiedFIFO(&nf);
int nbJobs = 0;
for (int j = 0; j < (impp.n_segments / 8 + ((impp.n_segments & 7) == 0 ? 0 : 1)); j++) {
......@@ -391,11 +392,13 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
encoder_implemparams_t *perJobImpp = (encoder_implemparams_t *)NotifiedFifoData(req);
*perJobImpp = impp;
perJobImpp->macro_num = j;
pushTpool(&gNB->threadPool, req);
nbJobs++;
}
while (nbJobs) {
notifiedFIFO_elt_t *req = pullTpool(&nf, &gNB->threadPool);
notifiedFIFO_elt_t *req = pullNotifiedFIFO(&nf);
if (req == NULL)
break; // Tpool has been stopped
delNotifiedFIFO_elt(req);
......
......@@ -32,6 +32,7 @@
#include "PHY/defs_gNB.h"
#include "common/utils/threadPool/thread-pool.h"
#include "common/utils/thread_pool/task_manager.h"
void free_gNB_ulsch(NR_gNB_ULSCH_t *ulsch, uint16_t N_RB_UL);
......@@ -57,7 +58,11 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
uint32_t frame,
uint8_t nr_tti_rx,
uint8_t harq_pid,
uint32_t G);
uint32_t G
#ifdef TASK_MANAGER_DECODING
, thread_info_tm_t* t_info
#endif
);
/*! \brief Perform PUSCH unscrambling. TS 38.211 V15.4.0 subclause 6.3.1.1
@param llr, Pointer to llr bits
......
......@@ -50,6 +50,11 @@
//#define DEBUG_ULSCH_DECODING
//#define gNB_DEBUG_TRACE
#include "common/utils/thread_pool/task_manager.h"
#include <stdint.h>
#include <time.h>
#include <stdalign.h>
#define OAI_UL_LDPC_MAX_NUM_LLR 27000//26112 // NR_LDPC_NCOL_BG1*NR_LDPC_ZMAX = 68*384
//#define DEBUG_CRC
#ifdef DEBUG_CRC
......@@ -180,6 +185,10 @@ static void nr_processULSegment(void *arg)
LOG_E(PHY, "ulsch_decoding.c: Problem in rate_matching\n");
rdata->decodeIterations = max_ldpc_iterations + 1;
#ifdef TASK_MANAGER_DECODING
completed_task_ans(rdata->ans);
#endif
return;
}
......@@ -220,6 +229,10 @@ static void nr_processULSegment(void *arg)
if (rdata->decodeIterations <= p_decoderParms->numMaxIter)
memcpy(ulsch_harq->c[r],llrProcBuf, Kr>>3);
#ifdef TASK_MANAGER_DECODING
completed_task_ans(rdata->ans);
#endif
}
int decode_offload(PHY_VARS_gNB *phy_vars_gNB,
......@@ -325,8 +338,13 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
uint32_t frame,
uint8_t nr_tti_rx,
uint8_t harq_pid,
uint32_t G)
{
uint32_t G
#ifdef TASK_MANAGER_DECODING
// This is a broken idea. But so is the code arquitecture
, thread_info_tm_t* t_info
#endif
)
{
if (!ulsch_llr) {
LOG_E(PHY, "ulsch_decoding.c: NULL ulsch_llr pointer\n");
return -1;
......@@ -434,9 +452,16 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
set_abort(&harq_process->abort_decode, false);
for (int r = 0; r < harq_process->C; r++) {
int E = nr_get_E(G, harq_process->C, Qm, n_layers, r);
#ifdef TASK_MANAGER_DECODING
ldpcDecode_t* rdata = &((ldpcDecode_t*)t_info->buf)[t_info->len];
assert(t_info->len < 16);
rdata->ans = &t_info->ans[t_info->len];
t_info->len += 1;
#else
union ldpcReqUnion id = {.s = {ulsch->rnti, frame, nr_tti_rx, 0, 0}};
notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(ldpcDecode_t), id.p, &phy_vars_gNB->respDecode, &nr_processULSegment);
ldpcDecode_t *rdata = (ldpcDecode_t *)NotifiedFifoData(req);
#endif
decParams.R = nr_get_R_ldpc_decoder(pusch_pdu->pusch_data.rv_index,
E,
decParams.BG,
......@@ -461,7 +486,12 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
rdata->ulsch = ulsch;
rdata->ulsch_id = ULSCH_id;
rdata->tbslbrm = pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes;
#ifdef TASK_MANAGER_DECODING
task_t t = { .args = rdata, .func = &nr_processULSegment };
async_task_manager(&phy_vars_gNB->man, t);
#else
pushTpool(&phy_vars_gNB->threadPool, req);
#endif
LOG_D(PHY, "Added a block to decode, in pipe: %d\n", r);
r_offset += E;
offset += ((harq_process->K >> 3) - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0));
......
......@@ -43,6 +43,7 @@
#include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h"
#include "executables/rt_profiling.h"
#include "nfapi_nr_interface_scf.h"
#include "common/utils/thread_pool/task_manager.h"
#define MAX_NUM_RU_PER_gNB 8
#define MAX_PUCCH0_NID 8
......@@ -718,7 +719,6 @@ typedef struct PHY_VARS_gNB_s {
notifiedFIFO_t L1_tx_out;
notifiedFIFO_t L1_rx_out;
notifiedFIFO_t resp_RU_tx;
tpool_t threadPool;
int nbSymb;
int num_pusch_symbols_per_thread;
pthread_t L1_rx_thread;
......@@ -729,6 +729,14 @@ typedef struct PHY_VARS_gNB_s {
void *scopeData;
/// structure for analyzing high-level RT measurements
rt_L1_profiling_t rt_L1_profiling;
#if defined(TASK_MANAGER_DECODING) && defined(TASK_MANAGER_CODING) && defined(TASK_MANAGER_DEMODULATION) && defined(TASK_MANAGER_RU) && defined(TASK_MANAGER_SIM)
task_manager_t man;
#elif !defined(TASK_MANAGER_DECODING) || !defined(TASK_MANAGER_CODING) || !defined(TASK_MANAGER_DEMODULATION) || !defined(TASK_MANAGER_RU) || !defined(TASK_MANAGER_SIM)
task_manager_t man;
tpool_t threadPool;
#else
tpool_t threadPool;
#endif
} PHY_VARS_gNB;
typedef struct puschSymbolProc_s {
......@@ -777,6 +785,9 @@ typedef struct LDPCDecode_s {
int offset;
int decodeIterations;
uint32_t tbslbrm;
#ifdef TASK_MANAGER_DECODING
task_ans_t* ans;
#endif
} ldpcDecode_t;
struct ldpcReqId {
......
......@@ -43,6 +43,20 @@
#include "assertions.h"
#include <time.h>
#include <stdint.h>
static
int64_t time_now_ns(void)
{
struct timespec tms;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &tms)) {
return -1;
}
int64_t nanos = tms.tv_sec * 1000000000 + tms.tv_nsec;
return nanos;
}
//#define DEBUG_RXDATA
//#define SRS_IND_DEBUG
......@@ -240,9 +254,14 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx,
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_gNB_TX + gNB->CC_id, 0);
}
#ifdef TASK_MANAGER_DECODING
static void nr_postDecode(PHY_VARS_gNB *gNB, ldpcDecode_t *rdata)
{
#else
static void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req)
{
ldpcDecode_t *rdata = (ldpcDecode_t*) NotifiedFifoData(req);
#endif
NR_UL_gNB_HARQ_t *ulsch_harq = rdata->ulsch_harq;
NR_gNB_ULSCH_t *ulsch = rdata->ulsch;
int r = rdata->segment_r;
......@@ -355,7 +374,11 @@ static void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req)
}
}
#ifdef TASK_MANAGER_DECODING
static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH_id, uint8_t harq_pid, thread_info_tm_t* t_info)
#else
static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int ULSCH_id, uint8_t harq_pid)
#endif
{
NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
nfapi_nr_pusch_pdu_t *pusch_pdu = &gNB->ulsch[ULSCH_id].harq_process->ulsch_pdu;
......@@ -401,8 +424,12 @@ static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int
//--------------------- ULSCH decoding ---------------------
//----------------------------------------------------------
int nbDecode =
nr_ulsch_decoding(gNB, ULSCH_id, gNB->pusch_vars[ULSCH_id].llr, frame_parms, pusch_pdu, frame_rx, slot_rx, harq_pid, G);
start_meas(&gNB->ulsch_decoding_stats);
#ifdef TASK_MANAGER_DECODING
int const nbDecode = nr_ulsch_decoding(gNB, ULSCH_id, gNB->pusch_vars[ULSCH_id].llr, frame_parms, pusch_pdu, frame_rx, slot_rx, harq_pid, G, t_info);
#else
int const nbDecode = nr_ulsch_decoding(gNB, ULSCH_id, gNB->pusch_vars[ULSCH_id].llr, frame_parms, pusch_pdu, frame_rx, slot_rx, harq_pid, G);
#endif
return nbDecode;
}
......@@ -737,6 +764,10 @@ int check_srs_pdu(const nfapi_nr_srs_pdu_t *srs_pdu, nfapi_nr_srs_pdu_t *saved_s
return 0;
}
static int cnt = 0;
int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx)
{
/* those variables to log T_GNB_PHY_PUCCH_PUSCH_IQ only when we try to decode */
......@@ -836,6 +867,13 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx)
}
}
#ifdef TASK_MANAGER_DECODING
ldpcDecode_t arr[16];
task_ans_t ans[16] = {0};
thread_info_tm_t t_info = {.buf = (uint8_t*)arr, .len = 0, .ans = ans};
#endif
int64_t const t0 = time_now_ns();
int totalDecode = 0;
for (int ULSCH_id = 0; ULSCH_id < gNB->max_nb_pusch; ULSCH_id++) {
NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id];
......@@ -933,13 +971,32 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx)
// LOG_M("rxdataF_comp.m","rxF_comp",gNB->pusch_vars[0]->rxdataF_comp[0],6900,1,1);
// LOG_M("rxdataF_ext.m","rxF_ext",gNB->pusch_vars[0]->rxdataF_ext[0],6900,1,1);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_ULSCH_PROCEDURES_RX, 1);
#ifdef TASK_MANAGER_DECODING
int const tasks_added = nr_ulsch_procedures(gNB, frame_rx, slot_rx, ULSCH_id, ulsch->harq_pid, &t_info);
#else
int const tasks_added = nr_ulsch_procedures(gNB, frame_rx, slot_rx, ULSCH_id, ulsch->harq_pid);
#endif
if (tasks_added > 0)
totalDecode += tasks_added;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_ULSCH_PROCEDURES_RX, 0);
}
}
++cnt;
#ifdef TASK_MANAGER_DECODING
if (totalDecode > 0) {
assert(totalDecode == t_info.len);
join_task_ans(t_info.ans, t_info.len);
for(int i = 0; i < t_info.len; ++i){
nr_postDecode(gNB, &arr[i]);
}
if(cnt % 1024 == 0)
printf("Decoding time %ld \n", time_now_ns() - t0);
}
#else
bool const loop = totalDecode > 0;
while (totalDecode > 0) {
notifiedFIFO_elt_t *req = pullTpool(&gNB->respDecode, &gNB->threadPool);
if (req == NULL)
......@@ -948,6 +1005,15 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx)
delNotifiedFIFO_elt(req);
totalDecode--;
}
<<<<<<< HEAD
=======
if(loop && (cnt % 1024 == 0))
printf("Decoding time %ld \n", time_now_ns() - t0);
#endif
stop_meas(&gNB->ulsch_decoding_stats);
>>>>>>> ac01afe8d2 (Decoding in RF Sim working)
for (int i = 0; i < gNB->max_nb_srs; i++) {
NR_gNB_SRS_t *srs = &gNB->srs[i];
if (srs) {
......
......@@ -50,6 +50,8 @@
#include "executables/nr-uesoftmodem.h"
#include "nfapi/oai_integration/vendor_ext.h"
#include "common/utils/thread_pool/task_manager.h"
//#define DEBUG_NR_ULSCHSIM
THREAD_STRUCT thread_struct;
......@@ -91,9 +93,15 @@ void deref_sched_response(int _)
exit(1);
}
#ifdef TASK_MANAGER_DECODING
int nr_postDecode_sim(PHY_VARS_gNB *gNB, ldpcDecode_t *rdata , int *nb_ok)
{
#else
int nr_postDecode_sim(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req, int *nb_ok)
{
ldpcDecode_t *rdata = (ldpcDecode_t*) NotifiedFifoData(req);
#endif
NR_UL_gNB_HARQ_t *ulsch_harq = rdata->ulsch_harq;
int r = rdata->segment_r;
......@@ -107,8 +115,16 @@ int nr_postDecode_sim(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req, int *nb_ok)
}
// if all segments are done
if (rdata->nbSegments == ulsch_harq->processedSegments)
if (rdata->nbSegments == ulsch_harq->processedSegments){
#ifdef TASK_MANAGER_DECODING
completed_task_ans(rdata->ans);
#endif
return *nb_ok == rdata->nbSegments;
}
#ifdef TASK_MANAGER_DECODING
completed_task_ans(rdata->ans);
#endif
return 0;
}
......@@ -407,7 +423,13 @@ int main(int argc, char **argv)
gNB = RC.gNB[0];
//gNB_config = &gNB->gNB_config;
#ifdef TASK_MANAGER_DECODING
int const num_threads = parse_num_threads("n");
init_task_manager(&gNB->man, num_threads);
#else
initTpool("n", &gNB->threadPool, true);
#endif
initNotifiedFIFO(&gNB->respDecode);
frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH)
frame_parms->N_RB_DL = N_RB_DL;
......@@ -588,8 +610,23 @@ int main(int argc, char **argv)
exit(-1);
#endif
#ifdef TASK_MANAGER_DECODING
ldpcDecode_t arr[16] = {0};
task_ans_t ans[16] = {0};
thread_info_tm_t t_info = {.buf = (uint8_t*)arr, .len = 0, .ans = ans };
int nbDecode = nr_ulsch_decoding(gNB, UE_id, channel_output_fixed, frame_parms, rel15_ul, frame, subframe, harq_pid, G, &t_info);
assert(nbDecode > 0);
#else
int nbDecode = nr_ulsch_decoding(gNB, UE_id, channel_output_fixed, frame_parms, rel15_ul, frame, subframe, harq_pid, G);
#endif
int nb_ok = 0;
#ifdef TASK_MANAGER_DECODING
join_task_ans(t_info.ans, t_info.len);
for(size_t i = 0; i < nbDecode; ++i){
ret = nr_postDecode_sim(gNB, &arr[i], &nb_ok);
}
nbDecode = 0;
#else
if (nbDecode > 0)
while (nbDecode > 0) {
notifiedFIFO_elt_t *req = pullTpool(&gNB->respDecode, &gNB->threadPool);
......@@ -597,7 +634,7 @@ int main(int argc, char **argv)
delNotifiedFIFO_elt(req);
nbDecode--;
}
#endif
if (ret)
n_errors++;
}
......@@ -624,6 +661,11 @@ int main(int argc, char **argv)
free(gNB->gNB_config.tdd_table.max_tdd_periodicity_list[i].max_num_of_symbol_per_slot_list);
free(gNB->gNB_config.tdd_table.max_tdd_periodicity_list);
#ifdef TASK_MANAGER_DECODING
void (*clean)(task_t* args) = NULL;
free_task_manager(&gNB->man, clean);
#endif
term_nr_ue_signal(UE, 1);
free(UE);
......
/*
/*
* 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.
......@@ -1944,4 +1944,5 @@ void nr_rrc_mac_config_req_cg(module_id_t module_id,
if (!mac->dl_config_request || !mac->ul_config_request)
ue_init_config_request(mac, mac->current_DL_BWP->scs);
}
......@@ -37,18 +37,35 @@ extern uint16_t NB_UE_INST;
/* configuration parameters for the rfsimulator device */
/* optname helpstr paramflags XXXptr defXXXval type numelt */
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
#define UICC_PARAMS_DESC { \
{"imsi", "USIM IMSI\n", 0, .strptr=&uicc->imsiStr, .defstrval="2089900007487", TYPE_STRING, 0 }, \
{"nmc_size" "number of digits in NMC", 0, .iptr=&uicc->nmc_size, .defintval=2, TYPE_INT, 0 }, \
{"key", "USIM Ki\n", 0, .strptr=&uicc->keyStr, .defstrval="fec86ba6eb707ed08905757b1bb44b8f", TYPE_STRING, 0 }, \
{"opc", "USIM OPc\n", 0, .strptr=&uicc->opcStr, .defstrval="c42449363bbad02b66d16bc975d77cc1", TYPE_STRING, 0 }, \
{"amf", "USIM amf\n", 0, .strptr=&uicc->amfStr, .defstrval="8000", TYPE_STRING, 0 }, \
{"sqn", "USIM sqn\n", 0, .strptr=&uicc->sqnStr, .defstrval="000000", TYPE_STRING, 0 }, \
{"dnn", "UE dnn (apn)\n", 0, .strptr=&uicc->dnnStr, .defstrval="oai", TYPE_STRING, 0 }, \
{"nssai_sst", "UE nssai\n", 0, .iptr=&uicc->nssai_sst, .defintval=1, TYPE_INT, 0 }, \
{"nssai_sd", "UE nssai\n", 0, .iptr=&uicc->nssai_sd, .defintval=0xffffff, TYPE_INT, 0 }, \
{"imeisv", "IMEISV\n", 0, .strptr=&uicc->imeisvStr, .defstrval="6754567890123413", TYPE_STRING, 0 }, \
};
//#define UICC_PARAMS_DESC { \
// {"imsi", "USIM IMSI\n", 0, .strptr=&uicc->imsiStr, .defstrval="2089900007487", TYPE_STRING, 0 }, \
// {"nmc_size" "number of digits in NMC", 0, .iptr=&uicc->nmc_size, .defintval=2, TYPE_INT, 0 }, \
// {"key", "USIM Ki\n", 0, .strptr=&uicc->keyStr, .defstrval="fec86ba6eb707ed08905757b1bb44b8f", TYPE_STRING, 0 }, \
// {"opc", "USIM OPc\n", 0, .strptr=&uicc->opcStr, .defstrval="c42449363bbad02b66d16bc975d77cc1", TYPE_STRING, 0 }, \
// {"amf", "USIM amf\n", 0, .strptr=&uicc->amfStr, .defstrval="8000", TYPE_STRING, 0 }, \
// {"sqn", "USIM sqn\n", 0, .strptr=&uicc->sqnStr, .defstrval="000000", TYPE_STRING, 0 }, \
// {"dnn", "UE dnn (apn)\n", 0, .strptr=&uicc->dnnStr, .defstrval="oai", TYPE_STRING, 0 }, \
// {"nssai_sst", "UE nssai\n", 0, .iptr=&uicc->nssai_sst, .defintval=1, TYPE_INT, 0 }, \
// {"nssai_sd", "UE nssai\n", 0, .iptr=&uicc->nssai_sd, .defintval=0xffffff, TYPE_INT, 0 }, \
// {"imeisv", "IMEISV\n", 0, .strptr=&uicc->imeisvStr, .defstrval="6754567890123413", TYPE_STRING, 0 }, \
// };
//
#define UICC_PARAMS_DESC {\
{"imsi", "USIM IMSI\n", 0, strptr:&(uicc->imsiStr), defstrval:"001010000000001", TYPE_STRING, 0 },\
{"nmc_size" "number of digits in NMC", 0, iptr:&(uicc->nmc_size), defintval:2, TYPE_INT, 0 },\
{"key", "USIM Ki\n", 0, strptr:&(uicc->keyStr), defstrval:"fec86ba6eb707ed08905757b1bb44b8f", TYPE_STRING, 0 },\
{"opc", "USIM OPc\n", 0, strptr:&(uicc->opcStr), defstrval:"c42449363bbad02b66d16bc975d77cc1", TYPE_STRING, 0 },\
{"amf", "USIM amf\n", 0, strptr:&(uicc->amfStr), defstrval:"8000", TYPE_STRING, 0 },\
{"sqn", "USIM sqn\n", 0, strptr:&(uicc->sqnStr), defstrval:"000000", TYPE_STRING, 0 },\
{"dnn", "UE dnn (apn)\n", 0, strptr:&(uicc->dnnStr), defstrval:"oai", TYPE_STRING, 0 },\
{"nssai_sst", "UE nssai\n", 0, iptr:&(uicc->nssai_sst), defintval:1, TYPE_INT, 0 }, \
{"nssai_sd", "UE nssai\n", 0, iptr:&(uicc->nssai_sd), defintval:0xffffff, TYPE_INT, 0 }, \
{"imeisv", "IMEISV\n", 0, strptr:&(uicc->imeisvStr), defstrval:"6754567890123413", TYPE_STRING, 0 }, \
};
static uicc_t** uiccArray=NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment